recvfrom适用于INADDR_ANY,但指定某些接口不起作用

时间:2014-11-25 19:22:33

标签: c++ sockets networking redhat rhel7

我编写了一个加入源特定组播组并接收udp组播数据包的程序:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <net/if.h>

typedef unsigned int        UINT32;

int join_ssm_group(int s, UINT32 group, UINT32 source, UINT32 inter) {
    struct ip_mreq_source imr; 
    imr.imr_multiaddr.s_addr  = group;
    imr.imr_sourceaddr.s_addr = source;
    imr.imr_interface.s_addr  = inter;
    return setsockopt(s, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, (char *) &imr, sizeof(imr));  
}

UINT32 LISTEN_INTERFACE = inet_addr("10.10.1.2");

int main(int argc, char *argv[]) {

    if (argc<3) {
        printf(" Use: %s <group> <source> <port>", argv[0]);
        return 1;
    }

    //  Make socket 
    int sd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);

    struct sockaddr_in Sender;
    socklen_t SenderAddrSize = sizeof( Sender );

    struct sockaddr_in binda;

    //  Bind it to listen appropriate UDP port
    binda.sin_family = AF_INET;
    binda.sin_port = htons( atoi(argv[3]));
      = INADDR_ANY;
    // binda.sin_addr.s_addr = LISTEN_INTERFACE;
    bind(sd,(struct sockaddr*)&binda, sizeof(binda));

    // Join to group
    join_ssm_group( sd, inet_addr(argv[1]), 
        inet_addr(argv[2]), 
        INADDR_ANY );

    char        buf[65536];
    UINT32      seq;

    while(1) {
        printf("try receive\n");
        int res=recvfrom(sd,(char*)buf,sizeof(buf),0, (struct sockaddr *)& Sender, &SenderAddrSize);
        printf("received\n");
        seq = *(UINT32*)buf;
        printf("scr=:%12s;\tseq=%6d;\tlen=%4d\n", inet_ntoa(Sender.sin_addr), seq, res);
    }

    return 0;
}

它工作正常,但请注意我正在使用binda.sin_addr.s_addr = INADDR_ANY;。 netstat显示了这个:

netstat -a | grep 16002
udp        0      0 0.0.0.0:16002           0.0.0.0:*

当我将其更改为binda.sin_addr.s_addr = LISTEN_INTERFACE;程序停止工作时 - 它无法接收数据包,它会挂起recvfrom。 netstat显示了这个:

netstat -a | grep 16002
udp        0      0 localhost.localdo:16002 0.0.0.0:*

在这两种情况下,tcpdump都显示数据在线,因此问题是我无法在特定接口上接收数据,只能在所有接口上接收数据。我正在使用RHEL 7,团队合作,而LISTEN_INTERFACE是相应VLAN的IP。为什么我的代码不起作用以及如何排除故障?出于性能原因,我不想使用INADDR_ANY - 监听所有接口比监听某些接口更昂贵。

将LISTEN_INTERFACE传递给join_ssm_groupbinda.sin_addr.s_addr

更新也不起作用。 BTW类似的Windows版本的此类代码可以在Windows Server 2008 R2下的同一台PC上运行,但它在RHEL 7中不起作用。我想我应该检查一下:

  • 如果RHEL 7在所需端口上的requreid接口上接收数据(答案为是,由tcpdump证明)
  • 如果socket正在侦听所需端口上的所需接口(答案是肯定的,由netstat证明了吗?)
  • 如果上述两个答案均为“是”,那么对recvfrom的调用怎么可能无法接收数据?

现在可能更多关于RHEL 7的问题,而不是关于c ++。

1 个答案:

答案 0 :(得分:1)

当您加入多播组时,您需要指定您正在侦听的相同接口,或者通过循环中的所有接口加入它。

然而,监听所有接口是常态。它不是“慢”,除非您有特定的理由限制谁可以连接,否则这是一个“好主意”。