摘 要: uIP作为一种广泛使用的轻量级嵌入式TCP/IP协议栈,其UDP协议的实现还不够完善,目前最新的1.0版本中仅实现了UDP客户端,尚没有实现UDP服务端。为此,对其进行了以下三方面的改进:UDP服务端口的初始化;接收到UDP客户端数据包后的端口号判断及匹配;UDP服务端发送报文后目的端口的释放。经过以上改进后,实验证明,uIP 1.0中的UDP实现了服务端的功能。
关键词: uIP;嵌入式TCP/IP协议栈;UDP;端口
随着嵌入式技术、网络技术的发展,实现网络互联已经成为嵌入式系统发展的一个必然趋势。在目前的技术条件下,越来越多的嵌入式系统选择了TCP/IP作为与其他计算机系统互联的网络协议。嵌入式TCP/IP协议栈已经成为嵌入式系统研究与应用中的一个重要领域。
由于嵌入式系统的软硬件资源都较为有限,大多数嵌入式系统中运行的TCP/IP协议栈均根据嵌入式系统的特点进行了相应的裁剪。目前应用比较广泛的嵌入式TCP/IP协议栈有:ucTCP-IP、LWIP、uIP、Linux TCP/IP等。其中uIP是专为8 bit和16 bit的嵌入式微控制器设计的微型TCP/IP协议栈, 它具有良好的互操作性, 并遵循RFC标准。uIP协议栈的特点是具有很小的代码量,运行时需要的内存很少,实现了常用的TCP/IP协议;代码注释详尽,可以用于商业或非商业用途[1]。由于具有上述特点,uIP被广泛应用在嵌入式系统的网络互联中。
1 uIP协议栈的体系结构
在使用uIP的嵌入式系统的软件体系结构中,uIP协议栈相当于一个代码库,它通过一系列的函数实现与底层硬件和上层应用程序的通信。uIP协议栈与系统底层和上层应用之间的关系如图1所示[2]。
从图1可以看出,uIP协议栈主要提供了uip_input()和uip_periodic()2个函数供系统底层调用。uIP协议栈与应用程序的主要接口是UIP_APPCALL()和UIP_UDP_APPCALL()。
uIP初始化时调用uip_init()函数,它的主要功能是初始化协议栈的监听端口,并把所有连接设置为关闭状态。当网络控制芯片驱动程序接收到一个数据包时,驱动程序将数据包放入全局缓冲区uip_buf中,同时把包的大小赋给全局变量uip_len。然后uIP的主控部分调用uip_input()函数,该函数将会根据数据包首部的协议标识处理这个包,并在需要时调用上层应用程序。当uip_input()返回时,一个输出数据包被放在同一个全局缓冲区uip_buf中,其大小赋给uip_len。如果uip_len是0,则说明没有包要发送,否则主控部分调用底层系统的发包函数将数据包发送到网络上[3]。
uIP周期计时用于驱动所有的uIP内部时钟事件。当周期计时激发后,每一个TCP连接都会调用uIP函数uip_periodic()。类似于uip_input()函数,uip_periodic()函数返回时,输出的IP包要放到uip_buf中,供底层系统查询uip_len的大小以决定是否发送。
由于使用TCP/IP的应用很多,因此应用程序作为单独的模块由用户实现。uIP提供一系列接口供用户程序调用,其中大部分接口是作为C的宏命令出现的,之所以这样做主要是考虑到速度、代码大小、效率和堆栈的使用。用户需要把对网络数据包的处理函数作为接口提供给uIP,并将这个函数定义为宏UIP_APPCALL()或者UIP_UDP_APPCALL()。UIP_APPCALL()是用户对TCP数据包的处理,UIP_UDP_APPCALL()是用户对UDP数据包的处理[4]。这样,uIP在接收到底层传来的数据包后,在需要送到上层应用程序处理的地方,直接调用UIP_APPCALL()或者UIP_UDP_APPCALL()即可,无需修改uIP。
2 uIP的UDP协议分析
2.1 UDP协议的实现
当uIP接收到一个UDP数据包后,首先从包头中取出数据的长度,然后重新对包进行校验,如果校验和不对,则直接丢掉这个包。如果校验无误,则对收到的包进行解复用。此时进行如下判断:
if(uip_udp_conn->lport != 0 &&
UDPBUF->destport == uip_udp_conn->lport &&
(uip_udp_conn->rport == 0 ||
UDPBUF->srcport == uip_udp_conn->rport) &&
(uip_ipaddr_cmp(uip_udp_conn->ripaddr, all_zeroes_addr) ||
uip_ipaddr_cmp(uip_udp_conn->ripaddr, all_ones_addr) || uip_ipaddr_cmp(BUF->srcipaddr, uip_udp_conn->ripaddr))) 上述代码中用到的主要变量、数据结构和函数的含义是:
uip_udp_conn->lport:本地UDP的源端口;
uip_udp_conn->rport:本地UDP的目的端口;
UDPBUF->srcport:接收到的数据包中的源端口;
UDPBUF->destport:接收到的数据包中的目的端口;
uip_udp_conn->ripaddr:本地UDP的目的IP地址;
BUF->srcipaddr:接收到的数据包中的源IP地址;
all_zeroes_addr:IP地址0.0.0.0;
all_ones_addr:IP地址255.255.255.255;
uip_ipaddr_cmp:IP地址比较函数,如果参加比较的两个IP地址相等,则返回1。
在uIP的实现中,如果以上判断语句为真,则对接收到的数据包进行处理,处理过程包括调用用户上层处理程序UIP_UDP_APPCALL()、构造新包的包头、计算新包的校验和等,然后将构造好的返回UDP包送到IP层进行处理。
2.2 UDP实现的不足
通过对uIP中UDP协议实现过程的分析可以发现,uIP没有提供初始化指定端口的函数,仅提供了一个对给定IP地址上给定端口建立UDP连接的函数,其原型是struct uip_udp_conn*uip_udp_new(uip_ipaddr_t*ripaddr,u16_t rport)。由于作为服务端运行时必须指定监听端口[5],而uIP没有提供此功能,因此要让uIP作为服务端运行,必须对uIP进行改进。
3 uIP中UDP协议的改进
3.1 增加初始化UDP服务端口
UDP协议作为服务端运行时,同TCP一样,必须在某个指定端口上监听客户端是否有数据包发送,如果有则还要接收数据包,这就要求在uIP记录UDP连接的数据结构uip_udp_conn中设置本地端口号一项,具体实现步骤如图2所示。
3.2 IP地址、端口号的判断及匹配
uip_process函数接收到网络控制芯片驱动程序送来的数据包后,当判断出收到的包是UDP包,执行2.1中的判断并且得到结果为真后,但还需要再做以下工作:如果uip_udp_conn中的目的端口号为0,则说明这是一个来自客户端的首次与服务端进行通信的数据包,服务端尚不知道此客户端的源端口,因此要把uip_udp_conn中的目的端口号设为收到的包中的源端口号,把uip_udp_conn中的目的IP地址设为收到的包中的源IP地址,具体代码如下:
if(uip_udp_conn->rport==0)
{
uip_udp_conn->rport=UDPBUF->srcport; memcpy(uip_udp_conn->ripaddr,UDPBUF->srcipaddr,sizeof(uip_ipaddr_t ));
}
3.3 UDP服务端目的端口的释放
UDP服务端的端口应该可以为来自多个客户端的请求提供服务,而UDP本身是一种无连接的传输层协议,因此在每次uIP作为服务端的UDP通信结束之后,还要释放uip_udp_conn中记录的目的端口号,以便下次接收来自不同IP、不同端口的新请求,否则当来自其他端口的请求到达时,uIP会不予响应。
在uIP的官方网站上下载到uIP 1.0的源代码之后,按照本文给出的几个步骤对uIP 1.0进行改造之后,利用gcc编译器把uIP 1.0编译成S3C2410上的可执行代码,把基于S3C2410的开发板作为UDP服务器,运行Windows XP的PC机作为客户端,两者通过一条交叉网线相联,在PC机上的测试程序发出UDP请求后,运行在S3C2410上的uIP可以对PC通过UDP协议发出的数据进行处理,并给PC作出正确的回复。实验证明,通过对uIP进行本文所述的改进之后,uIP具有了作为UDP服务端的能力。
参考文献
[1] http://www. sics. se/~adam/uip/index. php/Main_Page.
[2] ADAM D. The uIP embedded TCP/IP stack the uIP 1.0 reference manual. June 2006.
[3] ADAM D. Full TCP/IP for 8-bit architectures[C]. In Proceedings of the First International Conference on Mobile Applications, Systems and Services(MOBISYS 2003), San Francisco, May 2003.
[4] ADAM D, OLIVER S, THIEMO V, et al. Protothreads: simplifying event-driven programming of memory-constrained embedded systems[C]. In Proceedings of the Fourth ACM Conference on Embedded Networked Sensor Systems (SenSys 2006), Boulder, Colorado, USA, November 2006.
[5] FOROUZAN B A, FEGAN S C著. TCP/ZP协议簇[M]. 谢希仁等,译.北京:清华大学出版社,2006.