打印

看过UIP最好的入门**

[复制链接]
7021|26
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
6019赵文|  楼主 | 2011-3-27 15:44 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
一引言
  
  近几年来,人们对连接各种装置到一个现有的IP网络例如因特网上产生了浓厚的兴趣。为了可以通过因特网通讯,一个可实现的TCP/IP协议栈是必须的。对于由32位嵌入式处理器构建的中、高端网络接入嵌入式系统中,通常会运行一个集成有TCP/IP协议栈的操作系统。但是对于由8位和16位低端处理器构建的系统,由于其所具有的处理能力和资源十分有限,通常不运行操作系统,这就要求系统开发者根据应用的要求以及所选用的处理器的实际情况构建自己的TCP/IP协议栈。而TCP/IP协议的透明性掩盖了其实现的复杂性,从无到有构建一个协议栈是一件艰巨的任务,并且缺少有效的调试工具。uIPTCP/IP协议栈是使用于低端8位或16位微处理器构建的嵌入式系统的一个可实现的极小的TCP/IP协议栈。它可以自由分发和使用于商业和非商业目的。uIP使用C语言编写,使其方便于移植。并且uIP协议栈的代码大小和RAM的需求比其它一般的TCP/IP栈要小,这就使得它可以方便的应用到各种低端系统上。本文将简要描述uIP的实现方法,分析uIP协议栈的应用接口,并讨论如何将其应用到51系列单片机上。
  
  二uIP协议栈的实现方法简述
  
  uIP实现了TCP/IP协议集的四个基本协议:ARP地址解析协议,IP网际互联协议,ICMP网络控制报文协议和TCP传输控制协议。为了在8位16位处理器上应用,uIP协议栈在各层协议实现时采用有针对性的方法,保持代码大小和存储器使用量最小。
  
  1实现ARP地址解析协议时为了节省存储器,ARP应答包直接覆盖ARP请求包。
  
  2实现IP网络协议时对原协议进行了极大的简化,它没有实现分片和重组。
  
  3实现ICMP网络控制报文协议时,只实现echo(回响)服务。uIP在生成回响报文时并不重新分配存储器空间,而是直接修改echo请求报文来生成回响报文。将ICMP类型字段从“echo”类型改变成“echoreply”类型,重新计算校验和修改校验和字段。
  
  4uIP里的TCP没有实现发送和接收数据的滑动窗口。每个TCP连接的状态由uip_conn结构保存,uip_conn结构包括当地和远端的TCP端口编号,远程主机的IP地址,重发时间值,上一段重发的编号,和连接的段的最大尺寸等信息。一个uip_conn结构数组用于保存所有的连接,数组的大小为支持的同时连接的最大数量。为了减少储存器的使用量,在处理重发时uIP并不缓存发送的数据包,而是由应用程序在需要重发时重新生成发送的数据。
  
  三uIP协议栈的接口
  
  uIP协议栈为了具有最大的通用性,在实现时将底层硬件驱动和顶层应用层之外的所有协议集“打包“在一个“库“里。协议栈通过接口与底层硬件和顶层应用“通信“。通过这种方式,uIP具有极高的通用性和独立性,移植到不同系统和实现不同的应用都很方便,很好的体现了TCP/IP协议平台无关性的特点。uIP协议栈与系统底层和应用程序之间的接口关系如图(一)所示:
  
  1uIP协议栈与系统底层的接口
  
  uIP与系统底层的接口包括与设备驱动的接口和与系统定时器的接口两类。
  
  1.1uIP与设备驱动接口
  
  uIP通过函数uip_input()和全局变量uip_buf、uip_len来实现与设备驱动的接口。uip_buf用于存放接收到的和要发送的数据包,为了减少存储器的使用,接收数据包和发送数据包使用相同的缓冲区。uip_len表明接收发送缓冲区里的数据长度,通过判断uip_len的值是否为0来判断是否接收到新的数据,是否有数据要发送。当设备驱动接收到一个IP包并放到输入包缓存里(uip_buf)后,应该调用uip_input()函数。uip_input()函数是uIP协议栈的底层入口,由它处理收到的IP包。当uip_input()返回,若有数据要发送,则发送数据包放在包缓冲区里。包的大小由全局变量uip_len指明。如果uip_len是0,没有包要发送;如果uip_len大于0则调用网络设备驱动发送数据包。
  
  1.2uIP与系统计时接口
  
  TCP/IP协议要处理许多定时事件,例如包重发、ARP表项更新。系统计时用于为所有uIP内部时钟事件计时。当周期计时激发,每一个TCP连接应该调用uIP函数uip_periodic()。TCP连接编号作为参数传递给uip_periodic()函数。uip_periodic()函数检查参数指定的连接的状态,如果需要重发则将重发数据放到包缓冲区(uip_buf)中并修改uip_len的值。当uip_periodic()函数返回后,应该检查uip_len的值,若不为0则将uip_buf缓冲区中的数据包发送到到网络上。
  
  ARP协议对于构建在以太网上的TCP/IP协议是必须的,但对于构建与其他网络接口(例如:串行链路)上的TCP/IP则不是必需的。为了结构化的目的,uIP将ARP协议作为一个可添加的模块单独实现。因此,ARP表项的定时更新要单独处理。系统定时器对ARP表的更新进行定时,定时时间到则调用uip_arp_timer()函数对过期表项进行清除。
  
  2uIP协议栈与应用程序的接口
  
  应用程序作为单独的模块由用户实现,uIP协议栈提供一系列接口函数供用户程序调用。用户需将应用层入口程序作为接口提供给uIP协议栈,定义为宏UIP_APPCALL()。uIP在接收到底层传来的数据包后,若需要送上层应用程序处理,它就调用UIP_APPCALL()。uIP提供给应用程序的接口函数按功能描述如下:
  
  2.1接收数据接口:应用程序利用uip_newdata()函数检测是否有新数据到达。全局变量uip_appdata指针指向实际数据。数据的大小通过uip_datalen()函数获得。
  
  2.2发送数据接口:应用程序通过使用uIP函数uip_send()发送数据。uip_send()函数采用两个参数;一个指针指向发送数据起始地址,另一个指明数据的长度。
  
  2.3重发数据接口:应用程序通过测试函数uip_rexmit()来判断是否需要重发数据,如果需要重发则调用uip_send()函数重发数据包。
  
  2.4关闭连接接口:应用程序通过调用uip_close()函数关闭当前连接。
  
  2.5报告错误接口:uIP提供错误报告函数检测连接中出现的错误。应用程序可以使用两个测试函数uip_aborted()和uip_timedout()去测试那些错误情况。
  
  2.6轮询接口:当连接空闲时,uIP会周期性地轮询应用程序,判断是否有数据要发送。应用程序使用测试函数uip_poll()去检查它是否被轮询过。
  
  2.7监听端口接口:uIP维持一个监听知名TCP端口的列表。通过uip_listen()函数,一个新的监听端口打开并添加到监听列表中。当在一个监听端口上接收到一个新的连接请求时,uIP产生一个新的连接和调用该端口对应的应用程序。
  
  2.8打开连接接口:在uIP里面通过使用uip_connect()函数打开一个新连接。这个函数打开一个新连接到指定的IP地址和端口,返回一个新连接的指针到uip_conn结构。如果没有空余的连接槽,函数返回空值。
  
  2.9数据流控制接口:uIP提供函数uip_stop()和uip_restart()用于TCP连接的数据流控制。应用程序可以通过函数uip_stop()停止远程主机发送数据。当应用程序准备好接收更多数据,调用函数uip_restart()通知远程终端再次发送数据。函数uip_stopped()可以用于检查当前连接是否停止。
  
  四uIP在51系列单片机上的应用
  
  51系列单片机具有悠久的历史和广泛的应用,许多公司推出了具有更高的处理速度的51内核的8位单片机,被应用在各个领域内。因此使用uIP这种免费的TCP/IP协议栈解决由51内核的单片机构建的低端嵌入式设备的网络接入问题具有一定的代表性。下面将讨论利用uIP协议栈在51单片机上实现简单的WEBSERVER,远端用户可以通过浏览器访问存储在单片机系统上的WEB页面。

相关帖子

沙发
6019赵文|  楼主 | 2011-3-27 15:44 | 只看该作者
  
  硬件平台结构如图(二)所示:其中单片机选用PHILIPS公司的P89C51RD2,64K字节的串行EEPROM可以用于存储WEB页面。采用ISA接口的以太网接口芯片RTL8019AS连接到以太网上。通过MAX232实现与PC机的串行连接,可以显示调试信息。
  
  uIP协议栈是以函数库的形式提供的,本身不提供底层网络驱动和上层应用程序。因此为了完成指定的功能,开发者必须添加以下几个模块:底层RTL8019AS网卡芯片的驱动、应用层基于HTTP协议的WEBSERVER的实现、系统定时器。
  
  RTL8019AS的驱动主要包括三部分:init_8019as()函数完成网卡芯片的上电初始化,包括设定网卡物理地址,设定收发缓冲区位置和大小等;eth_send()函数完成数据的发送;eth_rcve()函数完成以太网数据的接收。底层网络设备驱动程序与uIP协议栈通过两个全局变量进行接口:变量uip_buf为收发缓冲区的首地址;uip_len为收发的数据长度。eth_send()函数将uip_buf里的uip_len长度的数据发送到以太网上。eth_rcve()函数将接收到的数据存储到uip_buf指定的缓冲区中,同时修改uip_len的值。
  
  uIP提供的源代码中包括一个基于HTTP协议的WEBSERVER示例,该WEBSERVER通过简单的文件系统在数据存储器中存储静态页面,同时具有CGI功能。用户可以参照该示例以及uIP提供给应用程序的接口函数说明实现自己的应用层功能。用户的应用程序中必须将UIP_APPCALL宏定义为该层的服务程序。例如:在示例程序中WEBSERVER的处理程序为httpd()函数,则要进行如下的宏定义#defineUIP_APPCALLhttpd。
  
  51系列单片机上都有2到3个定时计数器,可以选择其中的一个来为TCP/IP协议中与时间有关的事件定时。需要由用户处理的定时事件包括:为uip_periodic()函数的执行提供基准,还要为ARP表项的更新定时。uip_periodic()函数每0.5秒执行一次,ARP表项每10秒更新一次。
  
  uIP的设置单独包含在一个叫uipopt.h的头文件里,都是以宏的形式定义方便于修改。用户应根据自己的应用在uipopt.h文件里设置本地的物理地址、IP地址、网关地址、收发缓冲区的大小、支持的最大连接数、ARP表大小等等选项。
  
  添加了必须的模块,对uIP进行了正确地配置后,需要编写主程序函数。针对基于以太网的WEBSERVER应用,主程序在完成初始化后将不停的进行查询,如果有新数据包到达则送uip_input()函数处理;如果没有新数据包到达则处理定时事件。框架代码如下所示:
  

使用特权

评论回复
板凳
6019赵文|  楼主 | 2011-3-27 15:44 | 只看该作者
    void main(void) //主程序开始
  { …… //省略部分代码
  timer0_init(); //定时器初始化函数由开发者完成
  serial_init(); //串口初始化函数由开发者完成
  init_8019(); //网卡芯片初始化函数由开发者完成
  uip_init(); //uIP协议栈初始化函数由uIP协议栈提供
  httpd_init(); //HTTP应用程序初始化函数由WEB SERVER示例程序提供
  uip_arp_init();//ARP协议初始化函数由ARP模块提供
  while(1)
  { uip_len = eth_rcve(); //查询网卡是否有数据到来
  if(uip_len == 0) //如果没有数据到来则处理定时事件
  { if(0.5秒定时时间到)
  { for(i = 0; i < UIP_CONNS; i++) // UIP_CONNS为TCP连接数
  { uip_periodic(i); //处理每一个TCP连接
  if(uip_len > 0) //说明本连接有数据要发送或重发
  { uip_arp_out(); //由ARP处理部分添加以太网帧头
  eth_send(); //由网卡驱动程序发送
  }
  }//对应于:for()
  }// 对应于:if(0.5秒定时时间到)
  if(ARP表项更新时间到)
  uip_arp_timer(); //进行ARP表项更新
  }else if(uip_len > 0) //说明接收到新的数据包
  { if(BUF->type == htons(UIP_ETHTYPE_IP))//如果收到IP数据包
  { uip_arp_ipin(); //送ARP模块进行表项更新
  uip_len -= sizeof(struct uip_eth_hdr); //去除以太网帧头
  uip_input(); //送uip_input()进行处理
  if(uip_len > 0) //若uip_input()返回后uip_len不为零说明有数据要回送
  { uip_arp_out(); //由ARP部分添加以太网帧头
  eth_send(); //送交网卡驱动发送
  }//对应于:if()收到IP数据包
  }else if(BUF->type == htons(UIP_ETHTYPE_ARP))//如果收到ARP包
  { uip_arp_arpin(); //由uip_arp_arpin()处理,如果为应答包则进行表项
  //更新
  //如果为请求包,则构造应答数据包
  if(uip_len > 0) //说明收到的是ARP请求包,需要回送ARP应答包
  eth_send(); //送网卡驱动发送
  }//对应于:else if()收到ARP数据包
  }//对应于:else if() 说明接收到新的数据包
  }}
  以上实例在keilC51编译器下设置大模式,优化等级6(速度优先)进行编译,对uIP代码部分可以不做任何修改,对HTTP示例代码仅需针对类型表达进行极少量的修改即可编译通过。在硬件平台上运行良好。
  
  五总结
  
  uIP协议栈采用有效的方法和结构化的代码,使其存储器占用量很小并且可以很方便的应用到不同的工程项目中。同时它又是免费的可以自由使用于商业和非商业目的。uIP为低端嵌入式设备的网络接入提供了很好的解决方案,具有很高的应用价值。
  
  参考文献
  
  [1]DOUGLASE.COMER著,用TCP/IP进行网际互连(卷一、卷二)电子工业出版社,2000
  
  [2]JEREMYBENTHAM著,嵌入式系统Web服务器——TCP/IPLean机械工业出版社,2003
  
  [3]uIP协议栈网络站点http://dunkels.com/adam/uip/
  
  [4]REALTEK公司.RTL8019ASDatasheet,2000

使用特权

评论回复
地板
6019赵文|  楼主 | 2011-3-27 15:45 | 只看该作者
转:TCP/IP协议栈uIP在S3C44B0上的移植
  这个也不错
uIP在S3C44B0上的移植,无操作系统


首先必须说明的是,uIP的官方网址上,有很好的移植文档,大家应该以该文档为准。
作者的单位是Swedish Institute of Computer Science。
官方网址:http://www.sics.se/~adam/uip/
我使用的版本是1.0。
uIP是一个超轻量的TCP/IP协议栈,可以用于8位处理器和无操作系统环境。
uIP是瑞典大虾Adam Dunkels的作品。lwip也是这位大虾开发的,但是现在由另一个团队在维护。
版权:以我的poor的英文的理解,可以将uIP的源代码和二进制文件用于商业或其他用途。可以对源代码进行修改。
如果以源代码方式使用uIP,应该在源代码中保留uIP的版权说明。
如果以二进制方式使用uIP,应该在你的文档中包含uIP的版权说明。
也就是说,我们可以合法而且自地使用它,除非你把它说成是自己的作品。

由于移植很顺利,我没有仔细读源代码,这里简单说明一下自己对uIP的理解。
支持IP、ARP、TCP、UDP和ICMP(PING only)。
同时支持多个网络应用。
为了减少内存使用,在软件结构上没有按照协议分层,紧耦合。
我在ARM下编译,uIP的代码大小是10K字节左右,RAM使用2K字节多一点。应该还可以优化。
uIP仅使用一个数据缓冲(uip_buf),发送和接收都使用该缓冲区。因此:
TCP的重传功能,要借助应用层来实现。因为协议栈没有缓冲已发送的TCP分段。
基于异步事件的API。或者说应用应该怎样使协议栈运行起来:
协议栈初始化:包括设置IP地址、子网MASK,MAC地址。
应用在通过以太网驱动接收到以太网帧时,应调用uip_input(),对接收到的数据进行协议处理。
调用uip_input()前,应该将收到的以太网数据放在uip_buf中,并给uip_len变量赋值。
应用应该构造一个定时器,定时调用uip_periodic(),以帮助实现协议栈中需要定时处理的事务。
我选择的定时周期是20ms。
应用应提供一个处理协议栈事件的回调函数(CALLBACK),该回调函数也就是实现了网络应用(例如telnet)。
定义:#define UIP_APPCALL netApp_appcall //netApp_appcall就是我的协议栈事件处理函数。
在该函数中:
查询当前连接的端口,以判断对应哪一个网络应用。
通过调用uip_connected()等函数,判断返回值,以判断当前存在哪些事件并处理。
例如(uip_connected() == 1)表示连接建立。
例如(uip_newdata() == 1)表示收到新的应用数据,你应该在这里处理这些数据。
例如(uip_rexmit() == 1)表示应用应重传上一个TCP分段。
总的来说,这个API还是比较容易使用的。官方文档中提供了较详尽的API的说明和使用例子代码。
上面这个API与标准的socket接口很不一样。因为socket接口基于stop wait机制,需要multi task支持。
而uIP是面向无操作系统环境的。
uIP还提供了一个类似socket的接口Protosockets,那个接口需要一个protothread机制来实现。
所谓protothread很古怪,反正我是不会用的。

一个基本的uIP源代码集合:
uip.c uip.h
uip_arp.c uip_arp.h
uip_arch.h uip-conf.h uipopt.h
我在移植时,仅修改了uip-conf.h和uipopt.h。
uip-conf.h:
把“#define UIP_CONF_BYTE_ORDER LITTLE_ENDIAN”变成“#define UIP_CONF_BYTE_ORDER UIP_LITTLE_ENDIAN”。可能是个BUG。
配置你想打开或关闭的特性,例如是否支持UDP。
增加一个“#define UIP_CONF_IPV6 0”,以关闭ARM编译时的那么多警告。
增加“#include "netapp.h"”。这是你的网络应用的头文件,该头文件应该定义:
#define UIP_APPCALL
#define uip_tcp_appstate_t和#define uip_udp_appstate_t
#define UIP_APPSTATE_SIZE
uipopt.h:
对协议栈的一些高级配置,可以不修改直接使用。

我的板子是立宇泰的44b0开发板,上面有一个RTL8019AS。
8019AS的驱动程序用的是广东一位大虾的。
移植驱动时,要注意与硬件相关的两个问题:
使用GCS4,因此8019的基地址是0X8000000。
地址线用的是A8到A12,因此在访问8019时寄存器地址应<<8。
使用哪一个外中断脚作为8019的中断。
需要给8019AS驱动和uIP协议栈提供相同的MAC地址。

使用特权

评论回复
5
6019赵文|  楼主 | 2011-3-27 15:46 | 只看该作者
推荐的调试过程:
8019AS的寄存器中包含两个chip ID,是0x50和0x70。ID读出正确,说明8019AS的读写没有问题。
接收ARP包:
用计算机PING你的单板时,驱动程序应发生中断,收到ARP包。
ARP包的目的MAC地址是6个FF。
收到ARP请求包,进一步证明你的驱动程序是正确的。
将ARP请求包交给协议栈,协议栈应生成ARP响应包,通过驱动发送出去。
在计算机的命令行执行arp -a,应看到你的单板的IP地址与MAC地址。
接收IP包:
用计算机PING你的单板时,应收到封装在IP包中的ICMP包(ECHO)。
协议栈响应ECHO_REPLY类型的ICMP包,在计算机上就可以看到PING通了。
TCP:
找一个计算机上测试TCP的小程序,单板上做一个简单的TCP应用,测试连接的建立断开和接收发送。
结束语:
uIP很简单,能用在51单片机。我移植到ARM上有些小材大用。不过我只需要简单的网络应用,并且主要目的是学习。
我从开始下载uIP,到移植8019驱动,到TCP测试成功,用了整一个星期。在调试驱动时遇到一点小问题。
原来对TCP/IP协议栈只是泛泛的了解。
uIP的文档一定要通读。这么认真地写文档值得称许。

使用特权

评论回复
6
tlb| | 2011-3-28 08:42 | 只看该作者
这个要顶

使用特权

评论回复
7
XIANSir| | 2011-3-28 12:24 | 只看该作者
非常好,正需要,非常非常感谢楼主:handshake

使用特权

评论回复
8
a305566| | 2011-3-28 12:45 | 只看该作者
路过,顶起

使用特权

评论回复
9
luck851| | 2011-3-28 12:52 | 只看该作者
不错仔细看看

使用特权

评论回复
10
秋天落叶| | 2011-3-28 21:07 | 只看该作者
的确是不错的**

使用特权

评论回复
11
即时生效| | 2011-3-29 12:43 | 只看该作者
这个真的很适合入门啊!

使用特权

评论回复
12
sinadz| | 2011-3-29 20:11 | 只看该作者
**很不错,就是没看太明白

使用特权

评论回复
13
金鱼木鱼| | 2011-3-29 20:13 | 只看该作者
还是好好啃啃协议的手册吧

使用特权

评论回复
14
duzhh| | 2011-10-19 10:41 | 只看该作者
看到过了。

使用特权

评论回复
15
xsgy123| | 2011-10-19 16:28 | 只看该作者
很好的入门**,以文件的形式给出就更好了

使用特权

评论回复
16
火箭球迷| | 2011-10-20 18:45 | 只看该作者
不错的**

使用特权

评论回复
17
baidudz| | 2011-10-20 19:43 | 只看该作者
看着有点费劲

使用特权

评论回复
18
fan_qh| | 2012-3-15 13:26 | 只看该作者
uIP协议栈与应用程序的接口部分不是太明白???

使用特权

评论回复
19
fan_qh| | 2012-3-15 13:33 | 只看该作者
我如果想把底层接收到的数据拿到应用层,我应该调用那个函数???把接收到的数据取出来。。。

使用特权

评论回复
20
fan_qh| | 2012-3-15 15:54 | 只看该作者
最后接收到的数据放到哪去了???

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

350

主题

1515

帖子

1

粉丝