UIP 学习总结一
UIP是用C语言写的一个网络协议栈,UIP协议栈是TCP/IP协议栈的一个功能子集,它只能实现一次处理一个单独的网络接口,它支持IP、ICMP、UDP和TCP协议。UIP是一个非常精简的协议栈,适用于8位和16位微处理器构建基于以太网的应用。本文主要总结UIP的使用,对UIP源码的解析留待以后详细讲解。
一、获得UIP
CSDN上可以下载UIP协议栈,以及相应的文档资料。
二、 UIP组成结构
这里将要讲述下载后的UIP协议栈主要文件的作用。下载后的目录结构如下
其中uip文件时整个UIP协议栈文件,不需要更改。My_arch文件夹是移植相关的文件,在移植到具体的处理器平台时需要更改一些文件。
其中需要修改的文件有tapdev.h tapdec.c clock-arch.c clock-arch.huip_arch.c
Uip-conf.h。
Tapdev.c是关于所移植平台上对以太网的设备接口支持,需要提供以太网的初始化和读取网帧和发送网络帧的函数实现。
Clock-arch.c是uip的时钟支持,需要实现的函数有时钟初始化,获得时钟函数,一般情况下会使用系统时钟也可以用定时器提供时钟支持。主要在移植uc/os-ii时我们一般已经使用了系统时钟,那么为uip提供时钟支持的可以使用定时器完成,也可以使用UCOS的获得时钟节拍的函数。
Main.c是一个使用范例,下面将详细讲解这个文件。
三、 Main.c
Main.c主要包含有循环时钟的设置与初始化、arp时钟的初始化、以太网设备接口初始化、uip协议栈的初始化、设定本机的IP地址 网关和掩码、应用初始化
文件中包含以下函数调用
timer_set(&periodic_timer, CLOCK_SECOND / 2);//初始化轮询时钟,
timer_set(&arp_timer, CLOCK_SECOND * 10);//初始化arp时钟
tapdev_init();//以太网设备初始化
uip_init();//UIP协议栈初始化
uip_ipaddr(ipaddr, 192,168,0,2);
uip_sethostaddr(ipaddr);//主机IP
uip_ipaddr(ipaddr, 192,168,0,1);
uip_setdraddr(ipaddr);//网关
uip_ipaddr(ipaddr, 255,255,255,0);
uip_setnetmask(ipaddr);//掩码
httpd_init();//应用初始化,范例为一个web服务器
main.c中最重要的是一个循环,该循环查看网络上是否有到本机的数据帧以及本机是否有数据帧需要发送,为UIP提供了底层设备的支持。
while(1) {
uip_len = tapdev_read();//读取网络帧,返回长度,数据保存在uip_buf中
//大于0则说明有网络数据到来
if(uip_len > 0) {
//该数据类型为 IP包
if(BUF->type == htons(UIP_ETHTYPE_IP)) {
//通知ARP有IP包进来 进行ip 对mac地址转换并保存在arp缓存中
uip_arp_ipin();
uip_input();//调用uip_input函数对网络数据处理
/* Ifthe above function invocation resulted in data that
should be sent out on the network, theglobal variable
uip_len is set to a value > 0. */
if(uip_len> 0) {
uip_arp_out();//如果没有该ip的mac地址则要发送arp请求,所以在UDP应用中需要发送一次伪数据来获得mac地址
tapdev_send();//发送数据
}
} else if(BUF->type == htons(UIP_ETHTYPE_ARP)) {
uip_arp_arpin();//arp请求
/* Ifthe above function invocation resulted in data that
should be sent out on the network, theglobal variable
uip_len is set to a value > 0. */
if(uip_len> 0) {
tapdev_send();//arp回复
}
}
//超时则启动轮询
}else if(timer_expired(&periodic_timer)) {
timer_reset(&periodic_timer);
//遍历所有的TCP链接
for(i = 0; i < UIP_CONNS; i++) {
uip_periodic(i);
/* Ifthe above function invocation resulted in data that
should be sent out on the network, the globalvariable
uip_len is set to a value > 0. */
if(uip_len> 0) {
uip_arp_out();
tapdev_send();
}
}
#if UIP_UDP
for(i = 0; i < UIP_UDP_CONNS; i++) {
uip_udp_periodic(i);
/* Ifthe above function invocation resulted in data that
should be sent out on the network, theglobal variable
uip_len is set to a value > 0. */
if(uip_len> 0) {
uip_arp_out();
tapdev_send();
}
}
#endif /* UIP_UDP */
/* Call the ARP timer function every 10 seconds. */
if(timer_expired(&arp_timer)) {
timer_reset(&arp_timer);
uip_arp_timer();
}
}
}
return 0;
}
该循环是UIP协议栈的的基本需要重点理解。
四 、uip-conf.h
该文件为对UIP的配置文件。
主要配置选项有:uip TCP最大链接数、uip 最大监听端口数、uip缓存大小、uip数据顺序(是否颠覆)
UDP支持、UDP最大链接数。
其中和应用联系最为直接和紧密的是UIP_APPCALL 配置和 UIP_UDP_APPCALL
这两个宏分别需要指向uip回调的应用函数。
通常会如下配置
对于TCP应用
typedef struct { //…..成员} uip_tcp_appstate_t;//该结构体作为uip为每个链接保留的应用数据。
#ifndef UIP_APPCALL
#define UIP_APPCALLTcpApp//TcpApp是一个函数的名称,该函数与处理TCP相关
对于UDP应用
typedef struct {//….成员} uip_udp_appstate_t;
#ifndef UIP_UDP_APPCALL
#defineUIP_UDP_APPCALL UDPApp//UDPApp为函数名称,该函数与处理UDP相关
五、编写基于UIP的网络应用。
完成以上的工作后,就可以开始编写基于UIP的网络应用了。
具体的编写方法在uip文档中有详细的讲解,这里不多说了,主要注意一下几点。
1、 首先要区分不同的应用,为不同的应用分配不同的端口,然后再编写uip回调函数时先写
switch(uip_udp_conn->lport){
case HTONS(PORT) :
{
If(uip_newdata())
{
}else if(uip_poll())
{
}
//……其他情况分支
}
}
对于TCP应用类似。
UIP当前的TCP链接保存在uip_conn,UDP链接保存在uip_udp_conn结构体中。可以根据自己的需要灵活地设计回调函数。
2、 在加入实时操作系统支持后,在上面提及的循环中必须调用系统的延时函数,为其他的任务提供时间运行。
3、 UIP主要是为支持TCP协议而编写的,对于UDP的支持不是很充分,比如它无法实现服务器端的功能而需要对UIP协议栈进行一定的修改,这个在网上有一些资料讲解了,大家可以自己查询一下。
六 小结。
第一次写技术总结,很多方面经验不足,还望各位提提意见,多谢大家。在总结的时候才发现自己在很多地方还是理解的模糊不清的,这也是我开始坚持写总结的一个原因。这是对UIP的第一份总结,后面会有更加详细地分析和总结。2013了,大家都在努力,我也要,希望我找份好工作嘞,祝福我吧,新年快乐。