uIP
一个免费的
TCP/IP
栈
原文:
Adam Dunkels
2002年2月15日
翻译:张伟林 2003年5月17日
摘要
这个文档描述uIP TCP/IP栈。 uIP TCP/IP栈是使用于低至8位或16位微处理器的嵌入式系统的一个可实现的极小的TCP/IP协议栈。现时,uIP代码的大小和RAM的需求比其它一般的TCP/IP栈要小。
uIP栈使用一个基于编程模块事件去减少代码的大小和RAM的使用量。基于系统的底层和uIP之间的接口的回应会在文档里描述。系统的底层和uIP之间的接口是隐蔽的。文档后面包含了一些uIP应用编程例子。
uIP 的代码和这个文档的新版本可以在uIP的主页下载 http://dunkels.com/adam/uip/。
这个文档描述了uIP的0.6版。
1
引言
新近这些年里,人们对连接一个甚至只是小装置到一个现有的
IP
网络例如全球因特网的兴趣增加了。为了可以通过因特网通讯,一个可实现的
TCP/IP
协议栈是必须的。
uIP
是一个可实现的
TCP/IP
协议组件的一个非常重要的部分。
uIP
的实现目标是保持代码大小和储存器使用量最小。
现时,
uIP
代码的大小和
RAM
的需求比其它一般的
TCP/IP
栈要小。
uIP
使用
C
编程语言,它可以自用分发和使用于商业和非商业目的。
其它的
TCP/IP
栈,储存器经常用于数据缓存,等待一个数据已经成功送达的确应信号。
事实上,数据包丢失了,数据必须重发。有特色的是,数据是缓存在
RAM
里,如果需要重发数据,应用程序可以快速重生数据。例如,一个
HTTP
服务器服务的大部分是
ROM
里的静态和半静态页,不需要在
RAM
里缓存静态内容。所以,如果一个包丢失了,
HTTP
服务器可以容易地从
ROM
里重生数据。数据简单地从原先的位置读回来。
uIP
的优越性是允许应用程序参加数据重发。
这个文档由以下部分组成,第
2
节描述在系统和应用的立场上怎样使用
uIP
。第
3
节详细讨论协议实现细节。第
4
节覆盖了
uIP
的配置,第
5
节描述
uIP
的结构部分。最后,第
6
节提供一些
uIP
的应用编程实例。
2 uIP
的接口技术
uIP
可以看作是一个代码库为系统提供确定的函数。图
1
展示了
uIP
,系统底层和应用程序之间的关系。
uIP
提供三个函数到系统底层,
uip_init()
,
uip_input()
,和
uip_periodic()
。应用程序必须提供一个回应函数给
uIP
。当网络或定时事件发生时,调用回应函数。
uIP
提供许多函数和堆栈交互。
要注意的就是
uIP
提供的大部分函数是作为
C
的宏命令实现的,主要是为了速度,代码大小,效率和堆栈的使用。
图 1 uIP就好像一个库
2.1 uIP
应用接口
BSD
套节字接口使用于大部分的操作系统,它不适合微系统,因为在应用设计里,它逼使一个线程基于编程模块。一个多线程环境代价重大,因为,不但在线程管理里涉及增加代码的复杂性,而且保存每线程堆栈需要额外的储存器,还有执行任务切换的时间开销也摊派在这里。微型系统不会有足够的资源去实现一个多线程环境,因此需要这个环境的应用接口不适合
uIP
。
相反,
uIP
使用一个基于编程模块的事件,模块是实现应用程序作为一个
C
函数被
uIP
调用的地方,
uIP
响应一定的事件。
uIP
调用应用在,当接收数据时,当数据成功送达另一方中止连接时,当一个新的连接建立时,或者当数据需要重发时。
应用程序也周期性地循环等待新数据。应用程序只提供一个回应函数;它提升了应用程序处理不同的网络服务的不同的端口和连接的映射
uIP
与其它
TCP/IP
栈不同的是,当正在重发工作,它需要应用程序的帮助。其它
TCP/IP
栈缓存传输数据在储存器里,直到在连接的最后数据确应成功发送。如果数据需要重传,堆栈在没有通知应用程序下监视着重传工作。通过这种方法,当要等待一个确应,数据必须缓存在储存器里,如果产生一个重发,应用程序可以快速重新生成数据。为了减少储存器的使用量,
uIP
利用的论据是应用程序可以重新生成发送的数据和让应用程序参加重发。
2.1.1 uIP应用事件
应用程序必须作为
C
函数去实现,
uIP
在任何一个事件发生时调用
UIP_APPCALL()
。表
1
列出可能的事件和每个事件的对应测试函数。测试函数用于区别不同的事件。函数是作为
C
宏命令实现的,将会是零值或非零值。注意的是某些函数可以在互相连接时发生
(
也就是新数据可以在数据确应的同时到达
)
。
表
1: uIP
应用事件和对应的测试参数
一个数据包到达,确应先前发送到数据
|
uip_acked()
|
应用程序的新数据包已经到达
|
uip_newdata()
|
一个远程主机连接到监听端口
|
uip_connected()
|
一个到达远程主机的连接成功建立
|
uip_connected()
|
计时时间满重发
|
uip_rexmit()
|
计时时间满周期性轮询
|
uip_poll()
|
远程主机关闭连接
|
uip_closed()
|
远程主机中断连接
|
uip_aborted()
|
由于太多重传,连接中断
|
uip_timedout()
|
当应用程序调用时,
uIP
设置全局变量
uip_conn
去指向当前连接的
uip_conn
结构
(
图
5
)
。这可以用来区别不同的服务。一个典型的应用是检查
uip_conn->lport
(
当地
TCP
端口号
)
去决定那个服务连接应该提供。例如,如果值
uip_conn->lport
等于
80
,应用程序可以决定启动一个
HTTP
服务,值是
23
是启动
TELNET
服务。
2.1.2 接收数据
如果
uIP
测试函数
uip_newdata()
值为
1,
远程连接的主机有发送新数据。
uip_appdata
指针指向实际数据。
数据的大小通过
uIP
函数
uip_datalen()
获得。在数据不是被缓冲后,应用程序必须立刻启动。
2.1.3 发送数据
应用程序通过使用
uIP
函数
uip_send()
发送数据。
uip_send()
函数采用两个参数;一个指针指向发送数据和数据的长度。如果应用程序为了产生要发送的实际数据需要
RAM
空间,包缓存
(
通过
uip_appdata
指针指向
)
可以用于这方面。