OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 5900|回复: 7

分享一个UDP通信中,远程主机随机变化端口号的开发经验

[复制链接]

5

主题

11

帖子

0

精华

初级会员

Rank: 2

积分
62
金钱
62
注册时间
2016-6-4
在线时间
16 小时
发表于 2016-11-18 15:38:27 | 显示全部楼层 |阅读模式
手上开发一个项目,做一个本机设备和网络主机设备UDP通信。主机发送过一次数据包之后,本机每隔256ms循环给主机发送数据包。
主机每次启动的端口号是随机的。那么udp层在判断端口匹配的时候不能丢弃掉目标端口和Ip不匹配的包。
     if ((uncon_pcb == NULL) &&
              ((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) {
            /* the first unconnected matching PCB */
            uncon_pcb = pcb;
由于这段代码,那么在应用程序初始化的时候只能进行udp_bind,而不能进行udp_connect,以免 flag的值导致不能进入上述语句中if的条件。
我想了个办法,在udp的rev回调函数中,进行udp_connect
void udp_recv(void *arg,struct udp_pcb *upcb,struct pbuf *p,struct ip_addr *addr,u16_t port)
{
   ...
   udp_connect(upcb,addr,port);
   ...
}
下载进行测试,可以使用随机端口进行通信。但是出现了新的问题:
如果网络主机运行中故障重启,那么本机不重新启动的话无法连接,因为执行过udp_connect后,pcb->flag被标记为已经连接。
为了解决这个问题,我new了2个(或者n个)udp_pcb,pcb1和pcb2均绑定同一个port和ip,当udp收到数据后,从pcb池里找到其中一个,进入rev回调,检查udp找到的是哪一个,如果是pcb1,则udp_connect(pcb1),并且disconnect(pcb2),如果是pcb2,则相反执行。
void udp_recv(void *arg,struct udp_pcb *upcb,struct pbuf *p,struct ip_addr *addr,u16_t port)
{
       udp_pcb *pcb_ptr;
       pcb_ptr=find_pcb(upcb);
      
       udp_disconnect_all();
       udp_connect(pcb_ptr);
       .....
}
结果编译后,测试失败了。
仿真找了一下原因发现lwip默认不允许2个pcb绑定同一端口号和ip:
#if SO_REUSE
    else if (!ip_get_option(pcb, SOF_REUSEADDR) &&
             !ip_get_option(ipcb, SOF_REUSEADDR)) {
#else /* SO_REUSE */
    /* port matches that of PCB in list and REUSEADDR not set -> reject */
    else {
#endif /* SO_REUSE */
      if ((ipcb->local_port == port) &&
          /* IP address matches, or one is IP_ADDR_ANY? */
          (ip_addr_isany(&(ipcb->local_ip)) ||
           ip_addr_isany(ipaddr) ||
           ip_addr_cmp(&(ipcb->local_ip), ipaddr))) {
        /* other PCB already binds to this local IP and port */
        LWIP_DEBUGF(UDP_DEBUG,
                    ("udp_bind: local port %"U16_F" already bound by another pcb\n", port));
        return ERR_USE;
      }
根据源代码的注释,找到编译选项,并且打开
#ifndef SO_REUSE
#define SO_REUSE                        1
编译后测试依然不行,发现上述语句中的if选项始终执行导致
return ERR_USE;
原来是pcb->so_options没有变,我找了一下lwip没有提供修改该选项的接口方法,也许有我没找到,于是手动添加:
        udp_p2p = udp_new();
udp_p2p->so_options|=SOF_REUSEADDR;
最后编译测试成功,主机可以随时修改端口号,本机可以正常向修改端口号的主机发送数据。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

0

主题

19

帖子

0

精华

初级会员

Rank: 2

积分
93
金钱
93
注册时间
2016-9-30
在线时间
47 小时
发表于 2016-11-19 10:11:47 | 显示全部楼层
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165377
金钱
165377
注册时间
2010-12-1
在线时间
2111 小时
发表于 2016-11-21 22:43:05 | 显示全部楼层
谢谢分享
回复 支持 反对

使用道具 举报

20

主题

297

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1830
金钱
1830
注册时间
2013-7-29
在线时间
276 小时
发表于 2016-11-22 08:12:17 | 显示全部楼层
用的HDCP功能?
回复 支持 反对

使用道具 举报

0

主题

2

帖子

0

精华

新手入门

积分
30
金钱
30
注册时间
2015-10-22
在线时间
2 小时
发表于 2016-11-29 10:56:07 | 显示全部楼层
顶一个
回复 支持 反对

使用道具 举报

259

主题

806

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1887
金钱
1887
注册时间
2012-10-28
在线时间
353 小时
发表于 2017-1-4 10:38:40 | 显示全部楼层
你好,请教下,
udp_p2p = udp_new();  这个 udp_new 函数是你自己写的还是系统本身有提供啊 ???
回复 支持 反对

使用道具 举报

5

主题

11

帖子

0

精华

初级会员

Rank: 2

积分
62
金钱
62
注册时间
2016-6-4
在线时间
16 小时
 楼主| 发表于 2018-3-29 15:32:07 | 显示全部楼层
hpdell 发表于 2017-1-4 10:38
你好,请教下,
udp_p2p = udp_new();  这个 udp_new 函数是你自己写的还是系统本身有提供啊 ???

lwip提供的
回复 支持 反对

使用道具 举报

2

主题

474

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
6254
金钱
6254
注册时间
2018-6-27
在线时间
534 小时
发表于 2021-2-10 06:39:20 | 显示全部楼层
谢谢分享,学习学习。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-2-28 18:40

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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