C++ 如何为存在 2 个网卡的 UDP 多播设置套接字?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/361854/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to set up a socket for UDP multicast with 2 network cards present?
提问by
I'm trying to get udp multicast data using sockets and c++ (c). I have a server with 2 network cards so I need to bind socket to specific interface. Currently I'm testing on another server that has only one network card.
我正在尝试使用套接字和 c++ (c) 获取 udp 多播数据。我有一台带有 2 个网卡的服务器,所以我需要将套接字绑定到特定接口。目前我正在另一台只有一个网卡的服务器上进行测试。
When I use INADDR_ANY I can see the udp data, when I bind to specific interface I don't see any data. Function inet_addr is not failing (I removed checking for return value for now).
当我使用 INADDR_ANY 时,我可以看到 udp 数据,当我绑定到特定接口时,我看不到任何数据。函数 inet_addr 没有失败(我现在删除了对返回值的检查)。
Code is below. On a server with one network card, my IP address is 10.81.128.44. I receive data when I run as: ./client 225.0.0.37 12346
代码如下。在一个网卡的服务器上,我的IP地址是10.81.128.44。我在运行时收到数据:./client 225.0.0.37 12346
This gives me no data: ./client 225.0.0.37 12346 10.81.128.44
这没有给我任何数据:./client 225.0.0.37 12346 10.81.128.44
Any suggestions? (Hope the code compiles, I removed comments ...)
有什么建议?(希望代码编译通过,我删除了注释...)
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#include <iostream>
#include <string>
using namespace std;
#define HELLO_PORT 12345
#define HELLO_GROUP "225.0.0.37"
#define MSGBUFSIZE 256
int main(int argc, char *argv[])
{
string source_iface;
string group(HELLO_GROUP);
int port(HELLO_PORT);
if (!(argc < 2)) group = argv[1];
if (!(argc < 3)) port = atoi(argv[2]);
if (!(argc < 4)) source_iface = argv[3];
cout << "group: " << group << " port: " << port << " source_iface: " << source_iface << endl;
int fd;
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("socket");
exit(1);
}
u_int yes = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0)
{
perror("Reusing ADDR failed");
exit(1);
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = (source_iface.empty() ? htonl(INADDR_ANY) : inet_addr(source_iface.c_str()));
if (bind(fd,(struct sockaddr *)&addr, sizeof(addr)) < 0)
{
perror("bind");
exit(1);
}
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr(group.c_str());
mreq.imr_interface.s_addr = (source_iface.empty() ? htonl(INADDR_ANY) : inet_addr(source_iface.c_str()));
if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
{
perror("setsockopt");
exit(1);
}
socklen_t addrlen;
int nbytes;
char msgbuf[MSGBUFSIZE];
while (1)
{
memset(&msgbuf, 0, MSGBUFSIZE);
addrlen = sizeof(addr);
if ((nbytes = recvfrom(fd, msgbuf, MSGBUFSIZE, 0, (struct sockaddr *)&addr, &addrlen)) < 0)
{
perror("recvfrom");
exit(1);
}
cout.write(msgbuf, nbytes);
cout.flush();
}
return 0;
}
Thanks in advance ...
提前致谢 ...
回答by stefanB
After some searching and testing I found out herethat when bindingudp multicast socket we specify port and leave address empty e.g. specify INADDR_ANY
.
经过一番搜索和测试,我发现在这里,当结合UDP多播套接字我们指定端口和假地址空如指定INADDR_ANY
。
So the following
所以以下
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = (source_iface.empty() ?
htonl(INADDR_ANY) :
inet_addr(source_iface.c_str()));
should be look like:
应该是这样的:
COMMENT: If I understand your code you should be binding to your multicast address not the wildcard address. If you bind to the wildcard address you will be able to receive unicast packets on your multicast port. Binding to your multicast address will prevent this and ensure you only get multicast packets on that port.
EDIT: Fixed the code based on above comment, binding to multicast address, stored in 'group', as opposed to INADDR_ANY to receive only multicast packets sent to multicast address.
评论:如果我理解你的代码,你应该绑定到你的多播地址而不是通配符地址。如果绑定到通配符地址,您将能够在多播端口上接收单播数据包。绑定到您的多播地址将防止这种情况并确保您只能在该端口上获得多播数据包。
编辑:修复了基于上述注释的代码,绑定到多播地址,存储在“组”中,而不是 INADDR_ANY 只接收发送到多播地址的多播数据包。
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = (group.empty() ?
htonl(INADDR_ANY) :
inet_addr(group.c_str()));
This solved the problem. Adding IP_MULTICAST_IF
will not help because that is for selecting specific interface for sending udp data, the problem above was on receiving side.
这解决了问题。添加IP_MULTICAST_IF
无济于事,因为那是为了选择发送udp数据的特定接口,上面的问题是在接收端。
回答by David Allan Finch
I think you need to add IP_MULTICAST_IF
我认为您需要添加 IP_MULTICAST_IF
struct ip_mreq multi;
multi.imr_multiaddr.s_addr = inet_addr(group.c_str());
multi.imr_interface.s_addr = (source_iface.empty() ?
htonl(INADDR_ANY): inet_addr(source_iface.c_str()));
status = setsockopt(me->ns_fd, IPPROTO_IP, IP_MULTICAST_IF,
(char *)&multi.imr_interface.s_addr,
sizeof(multi.imr_interface.s_addr));
I hope that helps.
我希望这有帮助。