|
有阵子没发新帖了,这阵子搞了搞UIP在STM32上的移植,总结了一点经验,在这里分享非大家~协议栈的移植方法在这里不多说,因为这类的开发板例程很多,我在这里主要说一下用UIP作为服务器或者客户端实现TCP/UDP通信的方法,相信还是有一些人对此存在一些疑问的,希望能够帮到大家,呵呵~
1、TCP服务器方式;
这种方式的例程也是最多的,在这里简单说下步骤好了:
初始化网络:InitNet()-->创建监听端口:uip_listen(HTONS(1000))-->
设置回调函数:- void tcp_comm_appcall(void)
- {
- if (uip_aborted())
- {
- printf("uip_aborted!\r\n");
- aborted();
- }
- if (uip_timedout())
- {
- printf("uip_timedout!\r\n");
- timedout();
- }
- if (uip_closed())
- {
- printf("uip_closed!\r\n");
- closed();
- }
- if (uip_connected())
- {
- printf("uip_connected!\r\n");
- connected();
- }
- if (uip_acked())
- {
- acked();
- }
- /* 接收到一个新的TCP数据包,准备需要发送数据 */
- if (uip_newdata())
- {
- newdata();
- }
- if (uip_poll())
- {
- poll_event();
- }
- /* 当需要重发、新数据到达、数据包送达、连接建立时,通知uip发送数据 */
- if (uip_rexmit() || uip_newdata() || uip_acked() || uip_connected() || uip_poll())
- {
- senddata();
- }
- }
复制代码 -->然后等着被连接就行了
2、TCP客户端方式;
TCP的客户端和服务器的程序配置基本一样,首先会增加一个建立连接的函数,在UIP栈初始化之后即可调用,发起连接,函数如下:- /**********************************************************************************************************
- * 函 数 名: void tcp_comm_init(void)
- * 功能说明: 设备主动发起一个TCP链接
- * 形 参:无
- * 返 回 值: 无
- **********************************************************************************************************/
- void tcp_comm_connect(void)
- {
- uip_ipaddr_t ipaddr;
- uip_ipaddr(&ipaddr, 192,168,1,103);
- uip_connect(&ipaddr, HTONS(1001));
- }
复制代码 然后在回调函数“void tcp_comm_appcall(void)”中加入uip_poll的轮询,如下:- if (uip_poll())
- {
- poll_event();
- }
- static void poll_event(void)
- {
- struct tcp_comm_appstate *s = (struct tcp_comm_appstate *)&uip_conn->appstate;
-
- switch(uip_conn->rport)
- {
- case (HTONS(1001)):
- if(TCP_port1001_sendflag)
- {
- TCP_port1001_sendflag=0;
- s->textptr = "Hello World!";
- s->textlen = strlen((char *)s->textptr);
- }
- break;
- default:
- break;
- }
- }
复制代码 在函数“static void poll_event(void)”,借助UIP栈的轮询机制,当轮询到我们想要发送数据的端口1001时,并且数据发送标志位“TCP_port1001_sendflag”已经被置位,就可以实现向服务器主动发送数据。
3、UDP服务器方式
其实UIP的协议栈比较适合TCP通信,UDP通信做的并不好,比如在作为服务器的时候我们并不知道谁会连接我们,但是协议栈在第一次收到UDP数据包后会对包进行验证,结果必然验证不通过,包被丢弃。所以用UDP服务器方式,要先修改一下协议栈,修改部分就在uip.c中,大概1100行左右,代码如下:- #if UIP_UDP
- /* UDP input processing. */
- udp_input:
- /* UDP processing is really just a hack. We don't do anything to the
- UDP/IP headers, but let the UDP application do all the hard
- work. If the application sets uip_slen, it has a packet to
- send. */
- #if UIP_UDP_CHECKSUMS
- uip_len = uip_len - UIP_IPUDPH_LEN;
- uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];
- if(UDPBUF->udpchksum != 0 && uip_udpchksum() != 0xffff) {
- UIP_STAT(++uip_stat.udp.drop);
- UIP_STAT(++uip_stat.udp.chkerr);
- UIP_LOG("udp: bad checksum.");
- goto drop;
- }
- #else /* UIP_UDP_CHECKSUMS */
- uip_len = uip_len - UIP_IPUDPH_LEN;
- #endif /* UIP_UDP_CHECKSUMS */
- /*******************************添加代码起始***********************************/
- if(uip_udp_conn !=0&&(uip_udp_conn->rport!=UDPBUF->srcport
- ||uip_udp_conn->ripaddr!=UDPBUF->srcipaddr)) //如果是已经连接并且和接收到的端口号或者IP地址不一致
- {
- uip_udp_remove(uip_udp_conn); //删除连接
- uip_udp_conn->rport=UDPBUF->srcport; //将目的端口设置为收到的远端UDP包的端口
- memcpy(uip_udp_conn->ripaddr,UDPBUF->srcipaddr,sizeof(uip_ipaddr_t )); //将目的IP地址设置为收到的远端UDP包的源IP地址
- }
- if(uip_udp_conn->rport==0) //如果首次接收到某个远端UDP包
- {
- uip_udp_conn->rport=UDPBUF->srcport; //将目的端口设置为收到的远端UDP包的端口
- memcpy(uip_udp_conn->ripaddr,UDPBUF->srcipaddr,sizeof(uip_ipaddr_t )); //将目的IP地址设置为收到的远端UDP包的源IP地址
- }
-
- if(uip_udp_conn != 0)
- {
- uip_udp_bind(uip_udp_conn, HTONS(1999)); //绑定本地端口为LPORT,也就是LPORT-->RPORT 发数据
- }
- /*******************************添加代码截止***********************************/
- /* Demultiplex this UDP packet between the UDP "connections". */
复制代码 然后其余的初始化流程和TCP的方式一样,只是要添加属于UDP的回调函数,函数中内容如下即可,其余的这里不再多说。- if (uip_poll())
- {
- if(UDP_port7000_sendflag)
- {
- UDP_port7000_sendflag = 0;
- myudp_send("Hello World!\n",13);
- }
- }
- else if (uip_newdata())//接收到一个新的UDP数据包,准备需要发送数据
- {
- UDP_newdata();
- }
复制代码 4、UDP客户端方式
这种方式的初始化依旧和之前说的流程大致一样,只是要添加一个建立UDP连接的函数,函数内容如下:- struct uip_udp_conn *myudp_conn;
- void myudp_init(void)
- {
- //客户端
- uip_ipaddr_t ipaddr;//定义IP类型变量
- uip_ipaddr(ipaddr, 192,168,1,103); //远程IP为192.168.1.103
- if(myudp_conn != NULL)
- {
- uip_udp_remove(myudp_conn);//如果连接已经建立,则删除之
- }
-
- myudp_conn = uip_udp_new(&ipaddr, HTONS(7000));//建立到远程ipaddr,端口为7000的连接
- if(myudp_conn != NULL)
- {
- uip_udp_bind(myudp_conn, HTONS(LPORT));//绑定本地端口为1999,也就是1999-->7000 发数据
- }
- }
复制代码 该函数在初始化完成后即可调用,然后相应的回调函数如下,它主动发送数据的方式和TCP是一样,借助UIP栈的轮询机制,不再多说。- /*******************************************************************************
- * 函数名: void udp_comm_appcall(void) )
- * 参 数:
- * 返 回: 无
- * 功 能: UDP主函数
- **************************************************************************/
- void udp_comm_appcall(void)
- {
- //客户端模式
- if(myudp_conn->rport == (HTONS(7000)))
- {
- if (uip_poll())
- {
- if(UDP_port7000_sendflag)
- {
- UDP_port7000_sendflag = 0;
- myudp_send("Hello World!\n",13);
- }
- }
- else if (uip_newdata())
- {
- UDP_newdata();
- }
- }
- }
复制代码 |
阿莫论坛20周年了!感谢大家的支持与爱护!!
曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……
|