在 C++ 中的同一套接字上接收单播和多播
Receiving Unicast and Multicast on the Same Socket in C++
我需要在特定 IP 的同一套接字和端口上接收单播和多播 UDP。根据此处提出的其他问题,这应该是可能的。我可以设置所有选项并成功绑定,但我无法接收任何流量。它只是在 read()
调用时保持阻塞状态。
我尝试了很多不同的选项,例如 SO_BROADCAST
、SO_REUSEADDR
和 SO_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()
等的 none 失败了。我只是什么都不读。
我做错了什么吗? setsockopt
、bind
和 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_REUSEADDR
和 SO_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_REUSEADDR
或SO_REUSEPORT
。接收多播时,它确实允许您在同一个端口上有两个打开的套接字,这两个套接字都将接收多播流量,但是单播流量是去往两个,只去一个,还是轮询并没有明确定义。您也不需要 SO_BROADCAST
在您的接收器中,因为它只控制发送到广播地址的传出数据报(即 x.x.x.255)。
您加入多播组的方式看起来不错。请注意,如果您希望多播流量进入多个接口,那么您需要在每个接口上加入该组。
此外,如评论中所述,您应该使用 recvfrom
从 UDP 套接字接收数据。这允许您获取传入数据报的来源 IP/port,还允许您根据需要设置特定于套接字的标志。
我需要在特定 IP 的同一套接字和端口上接收单播和多播 UDP。根据此处提出的其他问题,这应该是可能的。我可以设置所有选项并成功绑定,但我无法接收任何流量。它只是在 read()
调用时保持阻塞状态。
我尝试了很多不同的选项,例如 SO_BROADCAST
、SO_REUSEADDR
和 SO_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()
等的 none 失败了。我只是什么都不读。
我做错了什么吗? setsockopt
、bind
和 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_REUSEADDR
和 SO_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_REUSEADDR
或SO_REUSEPORT
。接收多播时,它确实允许您在同一个端口上有两个打开的套接字,这两个套接字都将接收多播流量,但是单播流量是去往两个,只去一个,还是轮询并没有明确定义。您也不需要 SO_BROADCAST
在您的接收器中,因为它只控制发送到广播地址的传出数据报(即 x.x.x.255)。
您加入多播组的方式看起来不错。请注意,如果您希望多播流量进入多个接口,那么您需要在每个接口上加入该组。
此外,如评论中所述,您应该使用 recvfrom
从 UDP 套接字接收数据。这允许您获取传入数据报的来源 IP/port,还允许您根据需要设置特定于套接字的标志。