uip中文说明Word格式.docx
- 文档编号:19187885
- 上传时间:2023-01-04
- 格式:DOCX
- 页数:16
- 大小:33.45KB
uip中文说明Word格式.docx
《uip中文说明Word格式.docx》由会员分享,可在线阅读,更多相关《uip中文说明Word格式.docx(16页珍藏版)》请在冰豆网上搜索。
应用程序必须提供一个回应函数给uIP。
当网络或定时事件发生时,调用回应函数。
uIP提供许多函数和堆栈交互。
要注意的就是uIP提供的大部分函数是作为C的宏命令实现的,主要是为了速度,代码大小,效率和堆栈的使用。
图1uIP就好像一个库
2.1uIP应用接口
BSD套节字接口使用于大部分的操作系统,它不适合微系统,因为在应用设计里,它逼使一个线程基于编程模块。
一个多线程环境代价重大,因为,不但在线程管理里涉及增加代码的复杂性,而且保存每线程堆栈需要额外的储存器,还有执行任务切换的时间开销也摊派在这里。
微型系统不会有足够的资源去实现一个多线程环境,因此需要这个环境的应用接口不适合uIP。
相反,uIP使用一个基于编程模块的事件,模块是实现应用程序作为一个C函数被uIP调用的地方,uIP响应一定的事件。
uIP调用应用在,当接收数据时,当数据成功送达另一方中止连接时,当一个新的连接建立时,或者当数据需要重发时。
应用程序也周期性地循环等待新数据。
应用程序只提供一个回应函数;
它提升了应用程序处理不同的网络服务的不同的端口和连接的映射
uIP与其它TCP/IP栈不同的是,当正在重发工作,它需要应用程序的帮助。
其它TCP/IP栈缓存传输数据在储存器里,直到在连接的最后数据确应成功发送。
如果数据需要重传,堆栈在没有通知应用程序下监视着重传工作。
通过这种方法,当要等待一个确应,数据必须缓存在储存器里,如果产生一个重发,应用程序可以快速重新生成数据。
为了减少储存器的使用量,uIP利用的论据是应用程序可以重新生成发送的数据和让应用程序参加重发。
2.1.1uIP应用事件
应用程序必须作为C函数去实现,uIP在任何一个事件发生时调用UIP_APPCALL()。
表1列出可能的事件和每个事件的对应测试函数。
测试函数用于区别不同的事件。
函数是作为C宏命令实现的,将会是零值或非零值。
注意的是某些函数可以在互相连接时发生(也就是新数据可以在数据确应的同时到达)。
表1:
uIP应用事件和对应的测试参数
一个数据包到达,确应先前发送到数据
uip_acked()
应用程序的新数据包已经到达
uip_newdata()
一个远程主机连接到监听端口
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指针指向)可以用于这方面。
在一个时间里应用程序只能在连接中发送一块数据。
因此不可以在每个应用程序启用中调用uip_send()超过一次;
只有上一次调用的数据将会发出后才可以。
注意,调用uip_send()以后会改变某些全局变量,在应用函数返回前它不能被调用。
2.1.4重发数据
如果数据在网络中丢失,应用程序必须重发数据。
无论数据收到或没有收到,uIP保持跟踪,和通知应用程序什么时候察觉出数据是丢失了。
如果测试函数uip_rexmit()为真,应用程序要重发上一次发出的数据。
重发就好像原来那样发送,也就是通过uip_send()。
2.1.5关闭连接
应用程序通过调用uip_close()关闭当前连接。
这会导致连接干净地关闭。
为了指出致命的错误,应用程序可以中止连接和调用uip_abort()函数完成这个工作。
如果连接已经被远端关闭,测试函数uip_closed()为真。
应用程序接着可以做一些必要的清理工作。
2.1.6报告错误
有两个致命的错误可以发生在连接中,不是连接由远程主机中止,就是连接多次重发上一数据和被中止。
uIP通过调用函数报告这些问题。
应用程序使用两个测试函数uip_aborted()和uip_timedout()去测试那些错误情况。
2.1.7轮询
当连接空闲时,uIP在每一个时候周期性地轮询应用程序。
应用程序使用测试函数uip_poll()去检查它是否被轮询过。
2.1.8监听端口
uIP维持一个监听TCP端口列表。
通过uip_listen()函数,一个新的监听端口打开。
当一个连接请求在一个监听端口到达,uIP产生一个新的连接和调用应用程序函数。
如果一个新连接产生,应用程序被调用,测试函数uip_connected()为真。
2.1.9打开连接
作为uIP的0.6版,在uIP里面通过使用uip_connect()函数打开一个新连接。
这个函数打开一个新连接到指定的IP地址和端口,返回一个新连接的指针到uip_conn结构。
如果没有空余的连接槽,函数返回空值。
为了方便,函数uip_ipaddr()可以用于将IP地址打包进两个单元16位数组里,通过uIP去代表IP地址。
使用两个例子,在图2和图3展示。
第一个例子展示了怎样打开一个连接去远端TCP端口8080。
如果没有足够的TCP连接插槽去允许一个新连接打开,uip_connect()函数返回NULL和通过uip_abort()中止当前连接。
第二个例子展示怎样打开一个新连接去指定的IP地址。
这例子里没有错误检查。
voidconnect_example1_app(void){
if(uip_connect(uip_conn->
ripaddr,8080)==NULL){
uip_abort();
}
图2:
打开一个连接去当前连接的远端的端口8080
voidconnect_example2(void){
u16_tipaddr[2];
uip_ipaddr(ipaddr,192,168,0,1);
uip_connect(ipaddr,8080);
图3:
打开一个到主机192.168.0.1上端口8080的连接
2.1.10数据流控制
通过函数uip_stop()和uip_restart(),uIP提供存取TCP数据流的控制途径。
设想一个应用程序下载数据到一个慢速设备,例如磁盘驱动器。
如果磁盘驱动器的作业队列满了,应用程序不会准备从服务器接收更多的数据,直到队列排出空位。
函数uip_stop()可以用于维护流控制和停止远程主机发送数据。
当应用程序准备好接收更多数据,函数uip_restart()用于告知远程终端再次发送数据。
函数uip_stopped()可以用于检查当前连接是否停止。
2.2uIP/系统接口
从系统的立场看,uIP由3个C函数uip_init(),uip_input(),和uip_periodic()。
uip_init()函数用于初始化uIP堆栈和在系统启动期间调用。
当网络设备驱动器读一个IP包到包缓存时,调用函数uip_input()。
周期性运行是调用uip_periodic(),代表的是一秒一次。
调用uIP函数是系统的职责。
2.2.1uIP/设备驱动接口
当设备驱动放一个输入包在包缓存里(uip_buf),系统应该调用uip_input()函数。
函数将会处理这个包和需要时调用应用程序。
当uip_input()返回,一个输出包放在包缓存里。
包的大小由全局变量uip_len约束。
如果uip_len是0,没有包要发送。
2.2.2uIP/周期计时接口
周期计时是用于驱动所有uIP内部时钟事件,例如包重发。
当周期计时激发,每一个TCP连接应该调用uIP函数uip_periodic()。
连接编号传递是作为自变量给uip_periodic()函数的。
类似于uip_input()函数,当uip_periodic()函数返回,输出的IP包要放在包缓存里。
图4展示了调用uip_periodic()函数和监视输出包的一小段代码。
在这个特别的例子,函数netdev_send()是网络驱动的部分,将uip_buf数组的目录发出到网上。
for(i=0;
i<
UIP_CONNS;
++i){
uip_periodic(i);
if(uip_len>
0)
netdev_send();
图4:
周期计时和uIP的接口的例子代码.
2.3uIP函数总结
表2包含了所有uIP提供的函数
表2:
uIP函数总结
系统接口
uip_init()
uip_input()
uip_periodic()
初始化uIP
处理输入包
处理周期计时事件
应用程序接口
uip_listen()
uip_connect()
uip_send()
uip_datalen()
uip_close()
uip_abort()
uip_stop()
uip_stopped()
uip_restart()
开始监听端口
连接到远程主机
在当前连接发送数据
输入数据的大小
关闭当前连接
中止当前连接
停止当前连接
查找连接是否停止
重新启动当前连接
测试函数
uip_timeou()
uip_rexmit
远程主机已经发出数据
确应发出的数据
当前连接刚连上
当前连接刚关闭
当前连接刚中止
当前连接刚超时
数据重发
应用程序循环运行
其它
uip_mss()
uip_ipaddr()
htons(),ntohs()
获得当前连接的最大的段大小
将IP地址结构打包
在主机和网络之间转换字节次序
3实现协议
uIP实现了TCP/IP协议组的四个基本协议;
ARP[Plu82],IP[Pos81b],ICMP[Pos81a]和TCP[Pos81c]。
链路层协议例如PPP可以实现作为uIP下面的设备驱动。
应用层协议例如HTTP,FTP或SMTP可以实现为uIP之上的应用程序。
3.1地址解析协议|ARP
ARP协议映射了IP地址和以太网MAC物理地址,它在以太网上的TCP/IP操作是需要的。
ARP在uIP里实现的是包含一个IP到MAC地址的映射。
当一个IP包要在以太网上发出,查询ARP表,去找出包要发送去的MAC地址。
如果在表里找不到IP地址,ARP请求包就会发出。
请求包在网络里广播和请求给出IP地址的MAC地址。
主机通过发出一个ARP回应,响应请求IP地址。
当uIP给出一个ARP回应,更新ARP表。
为了节省储存器,一个IP地址的ARP请求覆盖发出的请求输出IP包。
它是假定上层将重新发送那些被覆盖了的数据。
每十秒表更新一次,旧的条目会被丢弃。
默认的ARP表条目生存时间是20分钟。
3.2网际协议|IP
uIP的IP层代码有两个职责:
验证输入包的IP头的正确性和ICMP和TCP协议之间多路复用。
IP层代码是非常简单的,由9条语句组成。
事实上,uIP的IP层极大地简化了,它没有实现碎片和重组。
3.3因特网信息控制协议|ICMP
在uIP里,只有一种ICMP信息实现了:
ICMP回响信息。
ICMP回响信息常常用于ping程序里的检查主机是否在线。
在uIP里,ICMP回响处理在一个非常简单的方式。
ICMP类型字段的改变是从\echo"
类型到\echoreply"
类型,从而ICMP调整校验和。
其次,IP地址里的IP头交换,包发回到原先的发送者。
3.4传输控制协议|TCP
为了减少储存器的使用,uIP里的TCP没有实现发送和接收数据的调整窗口。
输入的TCP段不会通过uIP缓存,但必须立即由应用程序处理。
注意这不能避免应用程序自己缓冲数据。
输出数据时,uIP不能在每个连接有超过一个未解决的TCP段。
3.4.1连接状态
在uIP,每个TCP连接的完全态包含当地和远端的TCP端口编号,远程主机的IP地址,重发时间值,上一段重发的编号,和连接的段的最大尺寸。
除此之外,每个连接也可以保持一些应用状态。
三个序列号是,期望接收的下一个字节的序列号,上一发送段第一字节的序列号,下一发送字节的序列号。
连接的状态由uip_conn结构表现,可以在图5看到。
一个uip_conn结构数组用于在uIP里保持所有的连接。
数组的大小等于同时的最大数量的连接,它在编译时间里设置(看第4节)。
structuip_conn{
u8_ttcpstateflags;
/*TCP状态和标志.*/
u16_tlport,rport;
/*当地和远端端口.*/
u16_tripaddr[2];
/*同等远端的IP地址.*/
u8_trcv_nxt[4];
/*我们期待接收的下一个序列号.*/
u8_tsnd_nxt[4];
/*上一个发送的序列号.*/
u8_tack_nxt[4];
/*通过从远端的下一个应答去应答序列号.*/
u8_ttimer;
/*重发时间r.*/
u8_tnrtx;
/*计算特殊段的重发数量.*/
u8_tmss;
/*连接的最大段大小.*/
u8_tappstate[UIP_APPSTATE_SIZE];
};
图5:
uip_conn结构
3.4.2输入处理
TCP输入处理和检验TCP校验和一起开始。
如果校验和是对的,在当前活动的TCP连接之间,源、目的端口号和IP地址复用包。
没有活动的连接符合输入包时,如果包不是一个监听端口的连接请求,包丢弃。
如果包是一个关闭端口的请求,uIP发一个RST包回应。
如果发现了一个监听端口,uip_conn结构数组扫描任何一个非活动连接。
如果发现一个,数组由新连接的端口号和IP地址填充。
如果连接请求携带一个TCPMSS(最大段大小)选择,它会分析,再次检查当前最大段大小MSS去决定当前连接的MSS,前后者的最小值会被选择。
最后,一个回应包发去确应开启连接。
应该将输入包送去一个已经活跃的连接,包的序列号和从远端主机来的期望的下一个序列号一起被检查(uip_conn结构里的rcv_nxt变量显示于图5)。
如果序列号不是期望得到的下一个,包会被丢掉和发一个ACK去指出期望得到的下一个序列号。
紧接着,检查输入包里的确应号,看看是否确应连接的所有输出数据。
它做了后,应用程序会知道这个事实的。
当序列号和确应号被检测过,依靠当前TCP状态,包将会被不同地处理。
如果连接在SYN-RCVD状态和输入包确应先前发送的SYNACK包,连接将会输入ESTABLISHED状态,调用应用函数去通知已经完全连接。
在连接的建立状态,如果有新数据由远端主机发送或者远端主机确应之前发送的数据,就调用应用函数。
当应用函数返回,TCP检查应用程序是否还有数据要发。
如果有,一个TCP/IP包会形成在包缓存里。
3.4.3输出处理
输出处理过程比输入处理直接和简单得多。
基本上,所有TCP和IP头字段由uip_conn结构里的值充满,计算TCP和IP的校验和。
当uip_process()函数返回,包通过网络设备驱动发出去。
3.4.4重发
当uIP通过periodic_timer被调用时,重发就进入运作(看段2.2.2)。
连接里有些特殊的数据(也就是数据发出了去但仍没有确应的)通过UIP_OUTSTANDING位在uip_conn结构里的TCP状态标志变量标记(图5)。
那个连接,时间变量减少。
当时间到达零,上一段必须重发和调用应用函数去做真正的重发。
如果一个特殊段重发编号超出一个可设置的界限,连接会结束和发一个RST段到远端连接结束,调用应用函数去通知它连接超时。
3.4.5重置TCP
TCP规格要求如果TCP头里的序列号和确应号在当前连接的接收窗口失去了,有RST(复位)标志设置的包必须断开连接。
为了减少代码的大小,uIP不严格遵守这个规定。
相反,如果一个有RST标志设置的包在连接里到达,连接会消灭那些不重要的序列号和确应号值。
这个行为将会在将来的uIP版本修订。
4配置uIP
uIP的设置隐藏在一个叫uipopt.h的单独头文件里。
这个文档不及包含了那些项目特性的设置选项(例如uIP网点的IP地址和同时发生连接的最大值),而且有结构和C编译器的特殊选项。
文档是独立的和有注释说明的。
5构做具体函数
当IP,ICMP和TCP协议在单一的C函数里实现(uip_process()函数),它们需要四个支持函数的帮助。
支持函数实现32位添加和计算校验和。
在uIP的0.4版本,支持函数的实现由实际的协议拆分,这是为了易于手工将支持函数汇编。
在支持函数频繁被调用后,有实际的增益是使那些函数运行得越来越快
四个支持函数中有两个是计算IP和TCP校验和,uip_ipchksum(),uip_tcpchksum(),另两个是执行TCP序列号的32位添加:
uip_add_ack_nxt()和uip_add_rcv_nxt()。
uIP分类包括简单的支持函数C实现。
uip_ipchksum()计算和返回网间IP头的校验和[BBP88],但没有进行检验和的位非操作。
IP头可以在uip_buf数组的头20字节找到。
uip_tcpchksum()函数计算TCP校验和。
TCP校验和是TCP头和数据的网间校验。
这个函数事实上有点复杂,TCP头和TCP数据可以在不同的储存器位置找到。
在uip_buf数组开头可以找到TCP头的20字节(也就是在&
uip_buf[20]),uip_appdata指针指向TCP数据的开头。
TCP数据的大小可以通过从整个包中减去IP和TCP头得出。
包的大小包含在uip_len这个全局变量里。
因为uIP不支持数据流里的IP或者TCP选择,IP和TCP头的大小是40字节。
6应用例子
这节提供一些简单的uIP应用例子
6.1一个简单的应用例子
第一个例子非常简单。
应用程序监听输入连接的端口1234。
当一个连接建立了,应用程序通过说“OK”回应所有发送给它的数据。
图6显示了应用程序的实现。
应用程序调用example1_init()初始化,uIP的回叫函数是example1_app(),在这个例子里,可设置的变量UIP_APPCALL应该要定义在example1_app。
初始化函数调用uIP函数uip_listen()去注册一个监听端口。
实际的应用函数example1_app()使用测试函数uip_newdata()和uip_rexmit()去确定为什么调用它。
如果调用应用程序是因为最远端发了数据给它,它回应一个"
ok"
。
如果调用应用函数是因为数据在网络里丢失和需要重发,它也发送一个"
注意,这个例子显示了一个完全的uIP应用。
应用程序不需要处理所有类型事件例如:
uip_connected()或uip_timedout()。
voidexample1_init(void){
uip_listen(1234);
voidexample1_app(void){
if(uip_newdata()||uip_rexmit()){
uip_send("
ok\n"
3);
图6:
一个非常简单的应用程序
6.2一个更高级的应用
第二个例子只是稍微比第一个高级一点,显示了程序中状态段怎样在uip_conn结构中使用。
这个应用程序和第一有些相似,它监听一个输入连接的端口和回应发送给它的数据一个"
最大的不同是当连接建立时,这个程序打印输出一个欢迎信息"
Welcome!
"
程序怎样实现,表面上是操作上的小改动产生效果上很大的不同。
复杂性增加的原因是如果数据在网络里丢失,程序必须知道那个数据需要重发。
如果"
信息丢失了,程序必须重发欢迎信息,如果其中一个"
信息丢失,程序必须发一个新的"
程序知道只要"
信息没有被远程主机确应,它就可能在网络里丢失了。
但一旦远程主机已发了一个确应回来,程序可以应为欢迎信息已经被接收,知道一些丢失的数据是一个"
信息。
因此程序可以在两个之中的一个状态:
在WELCOME-SENT状态,"
已经发出但没有被确应,或者WELCOME-ACKED状态,"
W
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- uip 中文 说明