简析UIP协议栈作为服务器/客户端实现TCP/UDP通信的方法
有阵子没发新帖了,这阵子搞了搞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;
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();
}
}
} 好帖!有含金量。谢谢楼主分享 好贴,谢谢LZ分享 谢谢,刚好用得着 请教下大神,用超声波的设备端和手机间通信,需要如何设计一套自有的通信协议,?
mark...uip tcp 服务器端 楼主的帖子,只有遇到问题才能体现出价值!
非常感谢!解决了我的问题。 {:smile:}{:smile:}谢谢分享!! 谢谢分享
页:
[1]