嵌入式系统中TCP/IP协议的精简与实现
通过对TCP/IP协议的分析,结合嵌入式系统的特点,挑选出一套精简、实用的TCP/IP协议子集,并详细介绍各协议层的实现过程。为嵌入式网络系统的开发提供一个较为简单且可行的思路。
1、引言
嵌入式网络系统就是在嵌入式设备上实现了网络互联功能的系统,一般要求嵌入式设备在软件上支持TCP/IP协议栈,实现有关的以太网通信协议。如何实现TCP/IP协议是嵌入式网络系统的关键技术之一,在嵌入式系统中应用TCP/IP协议的关键是,如何设计出精简、高效的TCP/IP协议子集,以此来减少对系统资源的占用。
目前使用广泛的TCP/IP协议栈有LWIP(Light Weight)、uIP、Linux IP等,这些协议栈具有一定的通用性,包含的协议内容比较全,同时也比较复杂。具体在移植到应用系统的时候要考虑的问题较多,各个库文件和全局变量相互交叉引用,若要针对特定系统进行精简,则牵一发而动全身,尤其是存储器的管理及上层协议与底层网络驱动的接口是两个最大的移植难题。
为了能对TCP/IP协议有较深的了解,又利于后期进行深入研究,我们在实现一具体的Internet网络报警系统时,进行自主的嵌入式TCP/IP协议开发。下文所介绍的TCP/IP协议系统由于精简而利于实现,且无需进行内存管理,适合传送数据量不大的嵌入式系统。在实现时,只要根据相应的数据帧格式,在各层完成相应的功能即可。非常适合研究学习之用,为嵌入式网络系统的开发提供一个较为可行且简单的思路。
2、协议的分析与选择
众所周知,TCP/IP是一个协议族,是几百种网络协议的集合。通用计算机系统有足够的资源支持通信协议在内核实现,但是嵌入式系统则不同,因为其CPU处理能力和系统存储能力都受到成本限制,充分利用资源、提高系统性价比是开发嵌入式应用的根本特点。所以要对TCP/IP协议进行精简以适应嵌入式系统。
下面我们以实际的Internet网络报警系统为例,设计一个较为精简的TCP/IP协议子系统。此系统采用32位ARM结构的三星S3C440BX处理器,加SMSC公司的以太网控制芯片LAN91C113,以及另外一些外围芯片组成。此系统要求经Internet传送一些现场采集的报警数据到远程站点,要求实时性好、传输速度快,但每次传输的数据量很少,只是简单的报警信息。根据这些要求,再经详细分析TCP/IP各协议层实现的功能,精简出的协议子集如图1:
层次 需要实现的协议
应用层 无
传输层 UDP|0">UDP
网络层P、ICMP中的Ping响应协议
链路层 ARP应答协议
图1 精简的TCP/IP协议子集
首先在链路层上,由于采用以太网的接入方式,系统必须要实现IEEE802.3所规定的CDMA/CD协议。CDMA/CD协议不需用户实现,此协议只要采用通用的以太网接口芯片就可支持。其次,为了保证系统在以太网中的通信,系统还需实现ARP应答协议,该协议用于将IP地址映射成以太网MAC地址。ARP的执行依靠维持一张表来完成IP地址和MAC的地址的映射。
在网络层,由于系统要求能够在Internet进行通信,因此系统要实现IP协议。IP层的代码有两个功能:验证到来的IP报文报头的正确性,并且对TCP和ICMP报文实行分流。因为不考虑IP的分片和重组,所以 IP层的代码非常的精简。为了能够测试系统与网络的连接,系统需要实现ICMP协议中的Ping应答协议,Ping应答协议主要是检查网络是否连通
在传输层, TCP为两台主机提供面向连接的、可靠的、无重复的双向数据流传输服务,TCP协议设计了严格的3次建立连接握手过程、4次关闭连接握手过程,这些过程的实现对系统资源的耗费非常大。而UDP的实现比较简单,它在某些嵌入式Internet的应用场合可以很好地应用。考虑到系统的简化及速度的要求,采用了UDP协议,为了确保UDP数据的到达,在应用程序中采用了重复发送、回复确认的方式来保证数据的正确性。
由于本嵌入式系统无HTTP、FTP等应用,所以应用层中的协议无需实现。
3、协议的实现
本系统由于协议比较精简,只保留了必须使用的一些协议,所以实现过程相对简单。实现过程中的一个总目标是系统开销要少,每一层之间要相互独立,内存操作简单。为了实现每一层的独立,实现上下层之间的数据透明传输。每层之间应通过一系列的函数进行数据传递,同时为了减少由于数据拷贝引入的系统开销,系统应通过指针操作,而不是数据拷贝方式,将缓冲区中的数据沿协议栈向上传递。
由于TCP/IP的各层协议的各种数据格式,在各种资料中都有详细说明,这里就不再一一介绍。只详细介绍总的结构、各层的功能及实现过程,为了便于调试,系统在实现时肯定是从底层开始,一层一层往上实现。
1) 首先公共数据结构的定义:如MAC地址格式、IP地址格式、系统的地址配置、缓冲区格式及大小。
其中MAC、IP地址格式都是固定的,系统的配置用于确定系统的IP地址及端口以及MAC地址值。在本系统中由于传送的数据有限,只定义了4个用于传送和接收数据的缓冲区每个长度为150字节。
2)网络驱动接口:由于网络驱动也是我们自己编制的,所以与上层结合起来很顺利,接收时采用中断机制,当收到网络中断就读取数据,根据包的种类分别传给ARP或IP协议,由每一层自行处理数据。发送时采用查询方式,应用层准备好数据,一层层封装并向下传递,最后经由网络驱动程序发送。
3) 链路层ARP协议的实现:
首先定义ARP数据帧头结构及ARP高速缓冲表,数据帧必须根据标准定义,高速缓冲表至少要含有IP地址及相对应的MAC地址两项。由于嵌入式系统所连接的对象数目较少且都比较固定,所以就去掉了缓冲表的定时刷新程序,这样可以大大减少系统的刷新开销。
这一部分的主要工作是:
a、根据上层数据包中的IP地址,在高速缓冲表中查出对应的MAC地址并填入包中相应位置。若表中没有相应MAC地址,则按照格式组装一个ARP请求包并发送,以得到对方MAC地址。
b、若收到ARP应答包,则更新ARP缓存表。
主要函数有:
struct pbuf * arp_packet(struct arpdata *q)// 把要发送的ARP数据打包成网络格式字节流;
struct mac *arp_lookup (struct ip *p) // 根据IP地址在ARP缓存表中查找MAC地址,若找不到则自动向网络广播ARP请求;
void arp_input(struct pbuf *p)// 从驱动程序传入ARP帧数据,如果是ARP请求则发送一个ARP应答包,如果是ARP应答则更新ARP缓存表;
4)网络层IP协议及Ping应答的实现:
首先定义数据结构IP及ICMP数据帧格式,这两者都要根据标准来定义。这一部分的主要工作有:
a、对上一层传下来的数据包,加上IP首部和IP校验和,发往下一层。以及对下一层传上来的数据包,进行校验和检查,若正确去掉IP首部,送往上一层。
b、为了便于测试要响应主机的PING程序,即如收到ICMP的回显请求包,则按照格式组装一个ICMP的回显应答包并发送。
主要函数有:
int ip_input(struct pbuf* p);//输入下一层的数据包,去掉IP首部传给上一层;
int ip_send_data(struct pbuf *p,int len,int type,struct ip dst_ip);//将上一层的数据加上IP首部,并向下一层发送;
void ip_packet(struct pbuf *p,struct IP_data *q,int len);//IP首部和数据打包;
U16 ip_chksum(U8 *p,int len);//IP检验和计算;
void icmp_input(struct pbuf *p) 如果ICMP的回显请求,则发一个应答包;
5)传输层UDP协议的实现:
根据标准定义UDP数据帧格式。这一部分的主要工作有:对应用层传下来的数据包,加上UDP首部和UDP校验和,发往下一层。以及对下一层传上来的数据包,进行校验和检查,若正确去掉UDP首部,提出数据送给应用层。需注意的是,要产生一个伪首部用于UDP数据检验和计算。
主要函数有:
void udp_input(struct pbuf *p);//从下一层输入UDP数据
void udp_output(U8 *str,struct ip dst_ip,U16 dst_port);//向下一层发送UDP数据
void makeup_pheader(struct ip *p,U16 len ,U8 *q);//产生伪首部用于UDP检验和计算
U16 udp_chksum(U8 *p,int len,U8 *p1,int len1);//计算UDP检验和
6)执行过程:
当本地系统有数据要发送时,首先在传输层将数据加上UDP首部,再到网络层加IP首部,然后到链路层从ARP表中查询相应的MAC地址,填入相应位置,并发给网络驱动程序传到以太网上。
图2是用SPYNET软件截取的本系统启动后第一次发送一串字符的整个网络协议应答过程,由于是第一次发送, ARP表为空。所以当发送UDP数据时找不到目的IP地址对应的MAC地址,系统先发ARP请求,等对方回一个ARP应答,得到对方MAC地址,然后再发UDP数据包。
- 嵌入式系统的定义与发展历史(11-15)
- 嵌入式系统亲密接触(11-22)
- 嵌入式系统设计中的USB OTG方案(02-01)
- 嵌入式线控驾驶系统开发过程中设计和测试考虑(02-02)
- 一个典型的嵌入式系统设计和实现 (02-02)
- DDR SDRAM在嵌入式系统中的应用(02-07)