搜索
bottom↓
回复: 8

简析UIP协议栈作为服务器/客户端实现TCP/UDP通信的方法

[复制链接]

出0入0汤圆

发表于 2013-11-1 12:32:58 | 显示全部楼层 |阅读模式
有阵子没发新帖了,这阵子搞了搞UIP在STM32上的移植,总结了一点经验,在这里分享非大家~协议栈的移植方法在这里不多说,因为这类的开发板例程很多,我在这里主要说一下用UIP作为服务器或者客户端实现TCP/UDP通信的方法,相信还是有一些人对此存在一些疑问的,希望能够帮到大家,呵呵~

1、TCP服务器方式;
这种方式的例程也是最多的,在这里简单说下步骤好了:
初始化网络:InitNet()-->创建监听端口:uip_listen(HTONS(1000))-->
设置回调函数:
  1. void tcp_comm_appcall(void)
  2. {
  3.     if (uip_aborted())
  4.         {
  5.                 printf("uip_aborted!\r\n");
  6.                 aborted();
  7.         }

  8.         if (uip_timedout())
  9.         {
  10.                 printf("uip_timedout!\r\n");
  11.                 timedout();
  12.         }

  13.         if (uip_closed())
  14.         {
  15.                 printf("uip_closed!\r\n");
  16.                 closed();
  17.         }

  18.         if (uip_connected())
  19.         {
  20.                 printf("uip_connected!\r\n");
  21.                 connected();
  22.         }

  23.         if (uip_acked())
  24.         {
  25.                 acked();
  26.         }

  27.         /* 接收到一个新的TCP数据包,准备需要发送数据 */
  28.         if (uip_newdata())
  29.         {
  30.                 newdata();
  31.         }

  32.         if (uip_poll())
  33.         {
  34.                 poll_event();
  35.         }        

  36.         /* 当需要重发、新数据到达、数据包送达、连接建立时,通知uip发送数据 */
  37.         if (uip_rexmit() ||        uip_newdata() || uip_acked() ||        uip_connected() || uip_poll())
  38.         {
  39.                 senddata();
  40.         }
  41. }
复制代码
-->然后等着被连接就行了

2、TCP客户端方式;
TCP的客户端和服务器的程序配置基本一样,首先会增加一个建立连接的函数,在UIP栈初始化之后即可调用,发起连接,函数如下:
  1. /**********************************************************************************************************
  2. *        函 数 名: void tcp_comm_init(void)
  3. *        功能说明: 设备主动发起一个TCP链接
  4. *        形    参:无
  5. *        返 回 值: 无
  6. **********************************************************************************************************/
  7. void tcp_comm_connect(void)
  8. {
  9.     uip_ipaddr_t ipaddr;

  10.     uip_ipaddr(&ipaddr, 192,168,1,103);
  11.     uip_connect(&ipaddr, HTONS(1001));
  12. }
复制代码
然后在回调函数“void tcp_comm_appcall(void)”中加入uip_poll的轮询,如下:
  1. if (uip_poll())
  2. {
  3.     poll_event();
  4. }
  5. static void poll_event(void)
  6. {
  7.     struct tcp_comm_appstate *s = (struct tcp_comm_appstate *)&uip_conn->appstate;
  8.    
  9.     switch(uip_conn->rport)
  10.     {
  11.       case (HTONS(1001)):
  12.         if(TCP_port1001_sendflag)
  13.         {
  14.             TCP_port1001_sendflag=0;
  15.             s->textptr = "Hello World!";
  16.             s->textlen = strlen((char *)s->textptr);
  17.         }        
  18.         break;
  19.       default:
  20.         break;
  21.     }
  22. }
复制代码
在函数“static void poll_event(void)”,借助UIP栈的轮询机制,当轮询到我们想要发送数据的端口1001时,并且数据发送标志位“TCP_port1001_sendflag”已经被置位,就可以实现向服务器主动发送数据。

3、UDP服务器方式
其实UIP的协议栈比较适合TCP通信,UDP通信做的并不好,比如在作为服务器的时候我们并不知道谁会连接我们,但是协议栈在第一次收到UDP数据包后会对包进行验证,结果必然验证不通过,包被丢弃。所以用UDP服务器方式,要先修改一下协议栈,修改部分就在uip.c中,大概1100行左右,代码如下:
  1. #if UIP_UDP
  2.   /* UDP input processing. */
  3. udp_input:
  4.   /* UDP processing is really just a hack. We don't do anything to the
  5.      UDP/IP headers, but let the UDP application do all the hard
  6.      work. If the application sets uip_slen, it has a packet to
  7.      send. */
  8. #if UIP_UDP_CHECKSUMS
  9.   uip_len = uip_len - UIP_IPUDPH_LEN;
  10.   uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];
  11.   if(UDPBUF->udpchksum != 0 && uip_udpchksum() != 0xffff) {
  12.     UIP_STAT(++uip_stat.udp.drop);
  13.     UIP_STAT(++uip_stat.udp.chkerr);
  14.     UIP_LOG("udp: bad checksum.");
  15.     goto drop;
  16.   }
  17. #else /* UIP_UDP_CHECKSUMS */
  18.   uip_len = uip_len - UIP_IPUDPH_LEN;
  19. #endif /* UIP_UDP_CHECKSUMS */
  20.     /*******************************添加代码起始***********************************/
  21.     if(uip_udp_conn !=0&&(uip_udp_conn->rport!=UDPBUF->srcport
  22.                 ||uip_udp_conn->ripaddr!=UDPBUF->srcipaddr))                                                  //如果是已经连接并且和接收到的端口号或者IP地址不一致        
  23.         {
  24.       uip_udp_remove(uip_udp_conn);                                                                                        //删除连接
  25.           uip_udp_conn->rport=UDPBUF->srcport;                                                        //将目的端口设置为收到的远端UDP包的端口
  26.                 memcpy(uip_udp_conn->ripaddr,UDPBUF->srcipaddr,sizeof(uip_ipaddr_t ));         //将目的IP地址设置为收到的远端UDP包的源IP地址
  27.     }
  28.     if(uip_udp_conn->rport==0)                                                                                                   //如果首次接收到某个远端UDP包
  29.         {
  30.             uip_udp_conn->rport=UDPBUF->srcport;                                                //将目的端口设置为收到的远端UDP包的端口
  31.                 memcpy(uip_udp_conn->ripaddr,UDPBUF->srcipaddr,sizeof(uip_ipaddr_t ));         //将目的IP地址设置为收到的远端UDP包的源IP地址
  32.         }
  33.    
  34.     if(uip_udp_conn != 0)  
  35.     {
  36.         uip_udp_bind(uip_udp_conn, HTONS(1999));                                                        //绑定本地端口为LPORT,也就是LPORT-->RPORT 发数据
  37.     }
  38.     /*******************************添加代码截止***********************************/
  39.   /* Demultiplex this UDP packet between the UDP "connections". */
复制代码
然后其余的初始化流程和TCP的方式一样,只是要添加属于UDP的回调函数,函数中内容如下即可,其余的这里不再多说。
  1. if (uip_poll())
  2.     {
  3.         if(UDP_port7000_sendflag)
  4.         {
  5.             UDP_port7000_sendflag = 0;
  6.             myudp_send("Hello World!\n",13);
  7.         }
  8.     }
  9.     else if (uip_newdata())//接收到一个新的UDP数据包,准备需要发送数据
  10.     {
  11.         UDP_newdata();
  12.     }
复制代码
4、UDP客户端方式
这种方式的初始化依旧和之前说的流程大致一样,只是要添加一个建立UDP连接的函数,函数内容如下:
  1. struct uip_udp_conn *myudp_conn;

  2. void myudp_init(void)
  3. {  
  4.     //客户端
  5.     uip_ipaddr_t ipaddr;//定义IP类型变量
  6.     uip_ipaddr(ipaddr, 192,168,1,103);   //远程IP为192.168.1.103
  7.     if(myudp_conn != NULL)
  8.     {
  9.         uip_udp_remove(myudp_conn);//如果连接已经建立,则删除之
  10.     }
  11.    
  12.     myudp_conn = uip_udp_new(&ipaddr, HTONS(7000));//建立到远程ipaddr,端口为7000的连接
  13.     if(myudp_conn != NULL)
  14.     {
  15.         uip_udp_bind(myudp_conn, HTONS(LPORT));//绑定本地端口为1999,也就是1999-->7000 发数据
  16.     }
  17. }
复制代码
该函数在初始化完成后即可调用,然后相应的回调函数如下,它主动发送数据的方式和TCP是一样,借助UIP栈的轮询机制,不再多说。
  1. /*******************************************************************************
  2. *        函数名: void udp_comm_appcall(void) )
  3. *        参  数:
  4. *        返  回: 无
  5. *        功  能: UDP主函数
  6. **************************************************************************/
  7. void udp_comm_appcall(void)
  8. {
  9.     //客户端模式
  10.     if(myudp_conn->rport == (HTONS(7000)))
  11.     {
  12.         if (uip_poll())
  13.         {
  14.             if(UDP_port7000_sendflag)
  15.             {
  16.                 UDP_port7000_sendflag = 0;
  17.                 myudp_send("Hello World!\n",13);
  18.             }
  19.         }
  20.         else if (uip_newdata())
  21.         {
  22.             UDP_newdata();
  23.         }   
  24.     }
  25. }
复制代码

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

发表于 2013-11-1 12:37:53 | 显示全部楼层
好帖!有含金量。谢谢楼主分享

出0入0汤圆

发表于 2013-11-1 14:43:16 | 显示全部楼层
好贴,谢谢LZ分享

出0入0汤圆

发表于 2013-11-28 19:00:37 | 显示全部楼层
谢谢,刚好用得着

出0入0汤圆

发表于 2013-11-28 19:45:44 | 显示全部楼层
请教下大神,用超声波的设备端和手机间通信,需要如何设计一套自有的通信协议,?

出0入0汤圆

发表于 2016-11-17 16:21:05 | 显示全部楼层
mark...uip tcp 服务器端

出0入24汤圆

发表于 2017-1-2 10:45:37 | 显示全部楼层
楼主的帖子,只有遇到问题才能体现出价值!
非常感谢!解决了我的问题。

出0入0汤圆

发表于 2018-1-4 10:25:52 | 显示全部楼层
谢谢分享!!

出0入0汤圆

发表于 2021-8-18 15:51:38 | 显示全部楼层
谢谢分享
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-3-29 18:45

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表