V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
yaron
V2EX  ›  问与答

请教大佬一个 Linux 组播的问题

  •  
  •   yaron · 2022-01-04 18:11:10 +08:00 · 896 次点击
    这是一个创建于 835 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Linux 下组播接收不到其他 IP 的数据。 不知道是不是程序代码哪里出错了,但在其他嵌入式机子上运行过是正常的.. ...

    情况:

    1. 机器 A 组播发送正常,其他 ip 能接受到机器 A 的数据
    2. 机器 A 组播接收失败,只能接收到自己发出去的数据,收不到其他 IP 组播发送的数据
    3. 其他 IP 直接单播发送给机器 A ,A 能接收到

    具体实现流程:

    1. 创建套接字

      #define UDP_MCAST_PORT 36000        //组播端口
      #define UDP_MCAST_ADDR "224.0.1.88" //组播地址
      
      auto socket = socket(AF_INET,SOCK_DGRAM,0);
      if (socket <= 0)
      return false;
      
    2. 设置端口复用

      int opt = 1;
      if (setsockopt(socket, SOL_SOCKET, SO_REUSEADDR ,(char*)&opt, sizeof(opt)) < 0)
      	return false;
      
    3. 绑定组播端口

      struct sockaddr_in addr;
      addr.sin_family = AF_INET;
      addr.sin_port = htons(UDP_MCAST_PORT);
      addr.sin_addr.s_addr = htonl(INADDR_ANY);
      
      if (bind(socket, (struct sockaddr*)&addr, sizeof(addr)) < 0)
      	return false;
      
    4. 加入组播

      struct ip_mreq mreq;
      mreq.imr_multiaddr.s_addr = inet_addr(UDP_MCAST_ADDR);
      mreq.imr_interface.s_addr = htonl(INADDR_ANY);
      
      if (setsockopt(socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mreq, sizeof(mreq)) < 0)
      	return false;
      
    5. 发送与接收

      //发送
      struct sockaddr_in addrSrv;
      addrSrv.sin_family=AF_INET;
      addrSrv.sin_addr.s_addr = inet_addr(UDP_MCAST_ADDR);
      addrSrv.sin_port=htons(UDP_MCAST_PORT);
      
      if (sendto(socket, data, dataLen, 0, (struct sockaddr *)&addrSrv,sizeof(addrSrv)) > 0)
      	return true;
      
      //接收
      struct sockaddr_in group_addr;
      socklen_t addr_len = sizeof(group_addr);
      
      int len = recvfrom(socket, buff, buffLen, 0, (struct sockaddr *) &group_addr, (int *)&addr_len);
      recvIP = inet_ntoa(group_addr.sin_addr);
      recvPort = group_addr.sin_port;
      
    8 条回复    2022-01-07 12:35:15 +08:00
    bitdepth
        1
    bitdepth  
       2022-01-04 18:23:04 +08:00 via iPad
    loop interface 有關閉?
    IF_MULTICAST_IF 是不是沒設置?
    ThinkZ
        2
    ThinkZ  
       2022-01-04 18:30:06 +08:00
    A 机多网卡?
    yaron
        3
    yaron  
    OP
       2022-01-04 18:34:36 +08:00
    @bitdepth 只有一张网卡,IF_MULTICAST_IF 是必须要设置的吗?请问下 loop interface 的作用是什么?我没配过这个参数,是指 IP_MULTICAST_LOOP 吗?
    yaron
        4
    yaron  
    OP
       2022-01-04 18:34:53 +08:00
    @ThinkZ 没有,只有一张网卡
    bitdepth
        5
    bitdepth  
       2022-01-05 12:12:20 +08:00 via iPad
    mreq.imr_interface.s_addr = htonl(INADDR_ANY);
    這句就是問題了,組播接受必綁網路卡位置,因為多張網路卡可加入同一組播組,但是物理上不同的網路
    yaron
        6
    yaron  
    OP
       2022-01-07 09:20:40 +08:00
    @bitdepth 我后面也有试过多网卡的程序,但还是接收不到组播数据。程序如下,将第 4 步骤改为:
    yaron
        7
    yaron  
    OP
       2022-01-07 09:21:09 +08:00
    @bitdepth 1. 加入组播

    ```c++
    struct ip_mreq mreq;
    mreq.imr_multiaddr.s_addr = inet_addr(UDP_MCAST_ADDR);
    mreq.imr_interface.s_addr = htonl(INADDR_ANY);

    //指定接口接收组播信息
    mreq.imr_interface.s_addr = inet_addr(localIP);

    if (setsockopt(socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mreq, sizeof(mreq)) < 0)
    return false;
    ```

    2. 指定组播出口网卡

    ```c++
    struct in_addr addr;
    memset(&addr, 0, sizeof(struct in_addr));

    addr.s_addr=inet_addr(localIP);
    if (setsockopt(socket, IPPROTO_IP, IP_MULTICAST_IF, (char*)&addr, sizeof(addr)) < 0)
    return false;
    ```
    bitdepth
        8
    bitdepth  
       2022-01-07 12:35:15 +08:00 via iPad
    代碼貼全吧,才有辦法批改
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5446 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 03:30 · PVG 11:30 · LAX 20:30 · JFK 23:30
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.