原文地址:http://blog.sina.com.cn/s/blog_9007cf3801015de2.html
uIP主流程:
while(1)
{
uip_len = tapdev_read(uip_buf);
if(uip_len > 0)
{
//收到的是IP数据,调用uip_input()处理
if(BUF->type == htons(UIP_ETHTYPE_IP))
{
uip_arp_ipin();//ARP地址检验
uip_input();
//处理完成后,如果uip_buf中有数据,则调用etherdev_send发送出去
if(uip_len > 0)
{
uip_arp_out();//以太网帧头封装
tapdev_send(uip_buf,uip_len);
}
}
//收到的是ARP数据,调用uip_arp_arpin()处理
else if(BUF->type == htons(UIP_ETHTYPE_ARP))
{
uip_arp_arpin();
if(uip_len > 0)
{
tapdev_send(uip_buf,uip_len);
}
}
}
//查看0.5S是否到了,到了则调用uip_periodic处理TCP超时程序
else if(timer_expired(&periodic_timer))
{
timer_reset(&periodic_timer);
for(i = 0; i < UIP_CONNS; i++)
{
uip_periodic(i);
if(uip_len > 0)
{
uip_arp_out();
tapdev_send(uip_buf,uip_len);
}
}
#if UIP_UDP
for(i = 0; i < UIP_UDP_CONNS; i++) {
uip_udp_periodic(i);
if(uip_len > 0) {
uip_arp_out();
tapdev_send(uip_buf,uip_len);
}
}
#endif
if(timer_expired(&arp_timer))
{
timer_reset(&arp_timer);
uip_arp_timer();
}
}
}
一般这个循环是不需要修改的,我暂时还没有碰到。现在试用了一下UDP,TCP,WEB,都不需要修改这个循环。
一些初始化函数:
uip_init();
// init MAC address
uip_ethaddr.addr[0] = EMAC_ADDR0;
uip_ethaddr.addr[1] = EMAC_ADDR1;
uip_ethaddr.addr[2] = EMAC_ADDR2;
uip_ethaddr.addr[3] = EMAC_ADDR3;
uip_ethaddr.addr[4] = EMAC_ADDR4;
uip_ethaddr.addr[5] = EMAC_ADDR5;
uip_setethaddr(uip_ethaddr);//设定以太网MAC地址
uip_ipaddr(ipaddr, 192,168,0,100);
uip_sethostaddr(ipaddr);//设置主机IP地址
uip_ipaddr(ipaddr, 192,168,0,1);
uip_setdraddr(ipaddr);//设定的是默认路由器地址
uip_ipaddr(ipaddr, 255,255,255,0);
uip_setnetmask(ipaddr);//设定子网掩码
接下来就要针对UDP或者是TCP做一些监听或连接:
针对UDP:
uip_ipaddr(ripaddr,192,168,0,101);//PC机IP地址
uip_udp_conn = uip_udp_new(&ripaddr,HTONS(1000));//建立远端端口1000,端口是以网络字节数学的,所以要用到HTONS
if( uip_udp_conn != NULL){
uip_udp_bind(uip_udp_conn,HTONS(3022));//绑定本地端口3022
}
针对TCP:
uip_listen(HTONS(23));//监听端口23
下面来看下网络调试助手,刚开始使用的时候,也是费了我好大尽的。

右上角的框是配置一些UDP的信息,分别是协议选择,本地IP地址以及本地端口号。一般在电脑中,端口号是随机配置的,当然也可以在助手中直接配置,方便在代码中调试。等connect成功之后,右下角红色框会出现远程IP地址及端口号的配置。如果是PC机和单片机相连,那么右下角就是单片机的一些信息。
至于TCP协议,一般都是TCP Server配置IP地址,端口号信息。服务器的端口号要与单片机中监听端口号相一致。
写下来说说这个协议栈的最最重要的函数,uip_process(u8_t flag)。TCP,UDP都用到这个函数。如果没什么特殊的要求,这个函数是不需要做任何修改的。按照报文,进行分析,没什么错误的话,最终都会调用到一个函数,UIP_APPCALL()。这个函数是需要用户自己编写的。有个宏,
#define UIP_UDP_APPCALL udp_appcall (UDP的用户接口函数)//适用于UDP
#define UIP_APPCALL tcp_appcall//适用于TCP
void udp_appcall( void )
{
if(uip_udp_conn->rport == HTONS(1000))
{
if(uip_poll())//如果是轮询的话
{
myudp_send("hello\n",6);
}
if(uip_newdata())//如果有新数据的话
{
newdata();
}
}
}
void tcp_appcall( void )
{
if(uip_newdata())
{
newdata();
}
}
上面是我编的两个调用函数。
void
uip_send(const void *data, int len)
{
if(len > 0) {
uip_slen = len;
if(data != uip_sappdata) {
memcpy(uip_sappdata, (data), uip_slen);
}
}
}
void myudp_send(char *str,short n)
{
char *nptr;
nptr = (char*)uip_appdata;
memcpy(nptr,str,n);
uip_udp_send(n);//发送n个数据
}
void newdata()
{
char *nptr;
short len;
len = uip_datalen();//读取数据长度
nptr = (char*)uip_appdata;//取得数据起始指针
if(len<4)
myudp_send("Please check the command!\n",26);
else if(strncmp(nptr,"getname",7)== 0)
myudp_send("My name is xiaoxu.",19);
else
// uip_send("Unkown command!\n",16);
myudp_send("Unkown command!\n",16);
}
这些也是我借鉴网上前辈的经验。uip_send这个函数,主要是发送应用层的数据,其他的会在其他函数中慢慢封装。
这个差不多就是整个uIP重要函数及要自己添加的函数。