您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 项目/工程管理 > 第二章 uIP协议栈分析V1.00
第二章uIP协议栈分析2.1uIP特性uIP由瑞典计算机科学学院(网络嵌入式系统小组)的AdamDunkels开发。其源代码由C语言编写,并完全公开,所有代码和相关说明文档可以到下载。最新版本是uIP1.0版本,本书移植和使用的版本正是此版本。uIP协议栈去掉了完整的TCP/IP中不常用的功能,简化了通讯流程,但保留了网络通信必须使用的协议,设计重点放在了IP/TCP/ICMP/UDP/ARP这些网络层和传输层协议上,保证了其代码的通用性和结构的稳定性。由于uIP协议栈专门为嵌入式系统而设计,因此还具有如下优越功能:(1)代码非常少,其协议栈代码不到6K,很方便阅读和移植。(2)占用的内存数非常少,RAM占用仅几百字节。(3)其硬件处理层、协议栈层和应用层共用一个全局缓存区,不存在数据的拷贝,且发送和接收都是依靠这个缓存区,极大的节省空间和时间。(4)支持多个主动连接和被动连接并发。(5)其源代码中提供一套实例程序:web服务器,web客户端,电子邮件发送程序(SMTP客户端),Telnet服务器,DNS主机名解析程序等。通用性强,移植起来基本不用修改就可以通过。(6)对数据的处理采用轮循机制,不需要操作系统的支持。由于uIP对资源的需求少和移植容易,大部分的8位微控制器都使用过uIP协议栈,而且很多的著名的嵌入式产品和项目(如卫星,Cisco路由器,无线传感器网络)中都在使用uIP协议栈。2.2uIP架构uIP相当于一个代码库,通过一系列的函数实现与底层硬件和高层应用程序的通讯,对于整个系统来说它内部的协议组是透明的,从而增加了协议的通用性。uIP协议栈与系统底层和高层应用之间的关系如图2-1所示。图2-1uIP在系统中的位置从上图可以看出,uIP协议栈主要提供了三个函数供系统底层调用。即uip_init(),uip_input()和uip_periodic()。其与应用程序的主要接口是UIP_APPCALL()。uip_init()是系统初始化时调用的,主要初始化协议栈的侦听端口和默认所有连接是关闭的。当网卡驱动收到一个输入包时,将放入全局缓冲区uip_buf中,包的大小由全局变量uip_len约束。同时将调用uip_input()函数,这个函数将会根据包首部的协议处理这个包和需要时调用应用程序。当uip_input()返回时,一个输出包同样放在全局缓冲区uip_buf里,大小赋给uip_len。如果uip_len是0,则说明没有包要发送。否则调用底层系统的发包函数将包发送到网络上。uIP周期计时是用于驱动所有的uIP内部时钟事件。当周期计时激发,每一个TCP连接都会调用uIP函数uip_periodic()。类似于uip_input()函数。uip_periodic()函数返回时,输出的IP包要放到uip_buf中,供底层系统查询uip_len的大小发送。由于使用TCP/IP的应用场景很多,因此应用程序作为单独的模块由用户实现。uIP协议栈提供一系列接口函数供用户程序调用,其中大部分函数是作为C的宏命令实现的,主要是为了速度、代码大小、效率和堆栈的使用。用户需要将应用层入口程序作为接口提供给uIP协议栈,并将这个函数定义为宏UIP_APPCALL()。这样,uIP在接受到底层传来的数据包后,在需要送到上层应用程序处理的地方,调用UIP_APPCALL()。在不用修改协议栈的情况下可以适配不同的应用程序。2.3uIP在MCS-51单片机上的移植1.为此项目建立一个keilC工程,建立src目录存放源文件。2.通过阅读uip-1.0\unix\main.c,了解uIP的的主循环代码架构,并将main.c放到src目录下。3.仿照uip-1.0\unix\tapdev.c写网卡驱动程序,与具体硬件相关。这一步比较费点时间,不过好在大部分网卡芯片的驱动程序都有代码借鉴或移植。驱动需要提供三个函数,以RTL9019AS驱动为例。etherdev_init():网卡初始化函数,初始化网卡的工作模式。u16_tetherdev_read(void):读包函数。将网卡收到的数据放入全局缓存区uip_buf中,返回包的长度,赋给uip_len。voidetherdev_send(void):发包函数。将全局缓存区uip_buf里的数据(长度放在uip_len中)发送出去。所以,收包和发包主要是操作uip_buf和uip_len。具体驱动分析可参考《第三章网络芯片的驱动》。4.由于uIP协议栈需要使用时钟,为TCP和ARP的定时器服务。因此使用单片机的定时器0用作时钟,每20ms让计数tick_cnt加1,这样,25次计数(0.5S)满了后可以调用TCP的定时处理程序。10S后可以调用ARP老化程序。对uIP1.0版本,增加了timer.c/timer.h,专门用来管理时钟,都放到src下。5.uIP协议栈的主要内容在uip-1.0\uip\下的uip.c/uip.h中,放到src下。如果需要ARP协议,需要将uip_arp.c和uip_arp.h也放到src下。6.uipopt.h/uip-conf.h是配置文件,用来设置本地的IP地址、网关地址、MAC地址、全局缓冲区的大小、支持的最大连接数、侦听数、ARP表大小等。需要放在src下,并且根据需要配置。在V1.00版本中对配置做了如下修改:(1)配置IP地址,默认先关IP,在初始化中再设定。#defineUIP_FIXEDADDR0#defineUIP_IPADDR0192#defineUIP_IPADDR1168#defineUIP_IPADDR21#defineUIP_IPADDR39#defineUIP_NETMASK0255#defineUIP_NETMASK1255#defineUIP_NETMASK2255#defineUIP_NETMASK30#defineUIP_DRIPADDR0192#defineUIP_DRIPADDR1168#defineUIP_DRIPADDR21#defineUIP_DRIPADDR31(2)使能MAC地址#defineUIP_FIXEDETHADDR1#defineUIP_ETHADDR00x00#defineUIP_ETHADDR10x4f#defineUIP_ETHADDR20x49#defineUIP_ETHADDR30x12#defineUIP_ETHADDR40x12#defineUIP_ETHADDR50x13(3)使能ping功能#defineUIP_PINGADDRCONF1(4)关闭主动请求连接的功能#defineUIP_ACTIVE_OPEN0(5)将uip_tcp_appstate_t定位u8_t类型。(6)由于单片机是大端结构,因此宏定义需要修改#defineUIP_CONF_BYTE_ORDERUIP_BIG_ENDIAN(7)暂时不移植打印信息,先关闭#defineUIP_CONF_LOGGING0(8)定义数据结构类型typedefunsignedcharu8_t;typedefunsignedintu16_t;typedefunsignedlongu32_t;7.如果使用keilC的小模式编译,需要在大部分的RAM的变量前增加xdata。8.data为keilC的关键词,代码中所有出现data的地方(主要是参数、局部变量、结构体成员)改为pucdata或ucdata。9.解决编译过程中的错误。uIP协议栈为C语言编写,编译过程中的问题比较少,并且容易解决。2.4uIP的主控制循环通过实际的代码说明uIP协议栈的主控制循环。voidmain(void){/*省略部分代码*//*设置TCP超时处理时间和ARP老化时间*/timer_set(&periodic_timer,CLOCK_CONF_SECOND/2);timer_set(&arp_timer,CLOCK_CONF_SECOND*10);/*定时器初始化*/init_Timer();/*协议栈初始化*/uip_init();uip_arp_init();/*应用层初始化*/example1_init();/*驱动层初始化*/etherdev_init();/*IP地址、网关、掩码设置*/uip_ipaddr(ipaddr,192,168,1,9);uip_sethostaddr(ipaddr);uip_ipaddr(ipaddr,192,168,1,16);uip_setdraddr(ipaddr);uip_ipaddr(ipaddr,255,255,255,0);uip_setnetmask(ipaddr);/*主循环*/while(1){/*从网卡读数据*/uip_len=etherdev_read();/*如果存在数据则按协议处理*/if(uip_len0){/*收到的是IP数据,调用uip_input()处理*/if(BUF-type==htons(UIP_ETHTYPE_IP)){uip_arp_ipin();uip_input();/*处理完成后,如果uip_buf中有数据,则调用etherdev_send发送出去*/if(uip_len0){uip_arp_out();etherdev_send();}}/*收到的是ARP数据,调用uip_arp_arpin()处理*/elseif(BUF-type==htons(UIP_ETHTYPE_ARP)){uip_arp_arpin();if(uip_len0){etherdev_send();}}}/*查看0.5S是否到了,到了则调用uip_periodic处理TCP超时程序*/elseif(timer_expired(&periodic_timer)){timer_reset(&periodic_timer);for(i=0;iUIP_CONNS;i++){uip_periodic(i);if(uip_len0){uip_arp_out();etherdev_send();}}/*查看10S是否到了,到了则调用ARP处理程序*/if(timer_expired(&arp_timer)){timer_reset(&arp_timer);uip_arp_timer();}}}return;}2.5uIP协议栈提供的主要接口提供的接口在uip.h中,为了减少函数调用造成的额外支出,大部分接口函数以宏命令实现的。1.初始化uIP协议栈:uip_init()2.处理输入包:uip_input()3.处理周期计时事件:uip_periodic()4.开始监听端口:uip_listen()5.连接到远程主机:uip_connect()6.接收到连接请求:uip_connected()7.主动关闭连接:uip_close()8.连接被关闭:uip_closed()9.发出去的数据被应答:uip_acked()10.在当前连接发送数据:uip_send()11.在当前连接上收到新的数据:uip_newdata()12.告诉对方要停止连接:uip_stop()13.连接被意外终止:uip_aborted()版本:V1.0初稿,欢迎指导作者:gateway邮箱:gatewaytech@126.comQQ:1079197758修改日期:2009.3.26
本文标题:第二章 uIP协议栈分析V1.00
链接地址:https://www.777doc.com/doc-6431192 .html