繁体   English   中英

在 C++ 中的同一套接字上接收单播和组播

[英]Receiving Unicast and Multicast on the Same Socket in C++

我需要在特定 IP 的同一个套接字和端口上同时接收单播和多播 UDP。 根据此处提出的其他问题,这应该是可能的。 我可以设置所有选项并成功绑定,但我无法接收任何流量。 它只是在read()调用时保持阻塞。

我尝试了许多不同的选项,例如SO_BROADCASTSO_REUSEADDRSO_REUSEPORT 我尝试将多播组地址设置为“0.0.0.0”,但失败了。 我只是不知道如何正确地做到这一点。

这是我当前状态的精简版:

struct sockaddr_in localSocket;

int sd = socket(AF_INET, SOCK_DGRAM, 0);
//error check here

int broadcast = 1;
//I have tried either one of these options, as well as SO_BROADCAST. 
// Now I am trying to use both
if ((setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char*)&broadcast, sizeof(broadcast)) < 0 || 
    (setsockopt(sd, SOL_SOCKET, SO_REUSEPORT, (char*)&broadcast, sizeof(broadcast)) < 0)) 
    //error handling here
else 
{
    memset((char*) &locakSocket, 0, sizeof(localSocket));
    localSocket.sin_family = AF_INET;
    //port that I want to receive on
    localSocket.sin_port = htons(port);
    //local IP that I want to receive on. I have tried "0.0.0.0" here as well, 
    //but I still do not receive anything
    localSocket.sin_addr.s_addr = inet_addr(IP); 
}

if(bind(sd,(struc sockaddr*)&kicakSicjetm suzeif(localSocket))<0)
    //error handling
else
{
    //trying to join multicast here:
    struct ip_mreq group;
    //IP address that the multicast is being sent from. 
    // I have tried "0.0.0.0" here too, but that fails.
    group.imr_multiaddr.s_addr = inet_addr("239.255.1.1");
    //local IP that I want to receive on. 
    I have tried skipping this line, but I still do not receive any traffic
    group.imr_interface.s_addr = inet_addr(IP);
}

if(setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &group, sizeof(group)) < 0)
    //error handling
else
{
    while(!terminate)
    {
        //this breakpoint is hit, but I never hit any line afterwards
        numbytes = read(sd,packet,sizeof(packet));
    }
}

由于我到达最后一行,我知道setsocketopt()bind()等都没有失败。 我只是从来没有读过任何东西。 我在做一些不正常的事情吗? setsockoptbind ,然后再次setsockopt感觉很奇怪,但这就是我的研究引导我的地方。

编辑:这是针对 linux 系统的。 有两个问题:
if ((setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char*)&broadcast, sizeof(broadcast)) < 0 || (setsockopt(sd, SOL_SOCKET, SO_REUSEPORT, (char*)&broadcast, sizeof(broadcast)) < 0))

localSocket.sin_addr.s_addr = inet_addr(IP);

我只是将这对setsockopt注释掉,这样我直到接近尾声才进行setsockopt 我使用了不正确的套接字选项,例如SO_REUSEADDRSO_REUSEPORT 此外,我正在绑定到我想要接收的本地 IP ,而不是绑定到IPADDR_ANY 感谢大家的帮助

假设您使用的是 Linux,当在同一个套接字上接收单播和多播流量时,您必须绑定到INADDR_ANY ,即 0.0.0.0。 如果绑定到特定接口,您将不会获得多播流量,如果绑定到多播地址,您将不会获得单播流量。

所以像这样设置你的绑定地址:

memset((char*) &locakSocket, 0, sizeof(localSocket));
localSocket.sin_family = AF_INET;
localSocket.sin_port = htons(port);
localSocket.sin_addr.s_addr = INADDR_ANY;

您也不想使用SO_REUSEADDRSO_REUSEPORT 接收多播时,它确实允许您在同一个端口上打开两个开放的 sockets,它们都将接收多播流量,但是单播流量是否流向两者、仅流向一个或轮询并没有明确定义。 您的接收器中也不需要SO_BROADCAST ,因为它只控制发送到广播地址(即 xxx255)的传出数据报。

您加入多播组的方式看起来不错。 请注意,如果您希望多播流量进入多个接口,那么您需要在每个接口上加入该组。

此外,如评论中所述,您应该使用recvfrom从 UDP 套接字接收数据。 这允许您获取传入数据报的源 IP/端口,还允许您在需要时设置特定于套接字的标志。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM