C语言 加入多播组时调用setsockopt时出现错误“没有这样的设备”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3187919/
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
Error "No such device" in call setsockopt when joining multicast group
提问by Mephi_stofel
I have a code in which send multicast datagrams. A critical piece of code:
我有一个发送多播数据报的代码。一段关键的代码:
uint32_t port;
int sockfd, err_ip;
const uint32_t sizebuff = 65535 - (20 + 8);
unsigned char *buff = (unsigned char *) malloc(sizebuff);
struct sockaddr_in servaddr, cliaddr;
struct in_addr serv_in_addr;
struct ip_mreq req;
port = str2uint16(cmdsrv->ipport);
bzero(buff, (size_t)sizebuff);
bzero(&servaddr, sizeof(servaddr));
bzero(&serv_in_addr, sizeof(serv_in_addr));
err_ip = inet_aton(cmdsrv->ipaddr, &serv_in_addr);
if(( err_ip != 0 ) && ( port != 0 )) {
servaddr.sin_family = AF_INET;
servaddr.sin_addr = serv_in_addr;
servaddr.sin_port = htons(port);
memcpy(&req.imr_multiaddr,&serv_in_addr,sizeof(req.imr_multiaddr));
req.imr_interface.s_addr = INADDR_ANY;
sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if( sockfd == -1 ) {
int outerror = errno;
char *retstr = "Couldn't open socket\n";
pthread_exit(retstr);
}
else {
struct in_addr ifaddr;
ifaddr.s_addr = INADDR_ANY;
int optres3 =
setsockopt( sockfd, IPPROTO_IP, IP_MULTICAST_IF, &ifaddr,
sizeof( ifaddr ));
if( optres3 == -1 ) {
int perrno = errno;
char *retstr = "Can't set IP_MULTICAST_IF for socket\n";
printf( "Error setsockopt: ERRNO = %s\n", strerror( perrno ));
printf( "%s",retstr );
pthread_exit(retstr);
}
unsigned char ttl = 32;
int optres2 =
setsockopt( sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
sizeof( ttl ));
if( optres2 == -1 ) {
int perrno = errno;
char *retstr = "Can't set IP_MULTICAST_TTL for socket\n";
printf("Error setsockopt: ERRNO = %s\n",strerror(perrno));
printf("%s",retstr);
pthread_exit(retstr);
}
int optres =
setsockopt( sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &req,
sizeof( req ));
if( optres == -1 ) {
int perrno = errno;
char *retstr = "Can't join to multicast-group\n";
printf("Error setsockopt: ERRNO = %s\n",strerror(perrno));
printf("%s",retstr);
pthread_exit(retstr);
}
// Bind port with socket
uint16_t cliport;
cliaddr.sin_family = AF_INET;
cliaddr.sin_addr.s_addr = INADDR_ANY;
if( strcmp( cmdsrv->ipport, "16011" ) == 0 ) {
cliport = str2uint16("16003");
cliaddr.sin_port = htons(cliport);
}
else if( strcmp( cmdsrv->ipport, "16012" ) == 0 ) {
cliport = str2uint16("16004");
cliaddr.sin_port = htons(cliport);
}
else {
printf("Device hasn't such port");
pthread_exit(NULL);
}
int bindres =
bind( sockfd, (struct sockaddr*)&cliaddr, sizeof( cliaddr ));
if( bindres == -1 ) {
int perrno = errno;
perror("Error in bind\n");
}
// ADD 1 BYTE
data rawdata;
rawdata.desc = 23;
printf( "SIZEOF = %d\n", sizeof( *( cmdsrv->cmd )));
memcpy( &rawdata.cmd, cmdsrv->cmd, sizeof( *( cmdsrv->cmd )));
printf( "RAWDATA: desc = %d, cmd = %d\n", rawdata.desc, rawdata.cmd );
int outerror = 0;
printf( "Send command to IP:\n addr = %s, port = %d\n",
inet_ntoa( servaddr.sin_addr ), ntohs( servaddr.sin_port ));
int size = sendto( sockfd, &rawdata, sizeof( rawdata ), 0,
(struct sockaddr*)&servaddr, sizeof( servaddr ));
if( size == -1 ) {
perror("Can't send command to socket");
}
...
Sometimes program executes successfully (at this moment I have IP - 192.168.80.122). I can capture my multicast datagram by wireshark. That's all OK.
有时程序会成功执行(此时我有 IP - 192.168.80.122)。我可以通过wireshark捕获我的多播数据报。没关系。
But if I change my IP to 192.168.1.2, I get error when is called
但是,如果我将 IP 更改为192.168.1.2,则在调用时会出错
int optres =
setsockopt( sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &req,
sizeof( req ));
And I can't even capture my multicast packet. Nothing is sent. Where's bug?
而且我什至无法捕获我的多播数据包。什么都没有发送。哪里有毛病?
回答by Aditya Sehgal
If it works for one IP but not for another, maybe thiscan help.
如果它适用于一个 IP 而不适用于另一个 IP,也许这会有所帮助。
What does "IP_ADD_MEMBERSHIP: No such device" mean?
It means that the tool is trying to use multicast but the network interface doesn't support it There are two likely causes:
Your machine doesn't have multicast support enabled. For example, on Linux and FreeBSD it is possible to compile a kernel which doesn't support multicast.
You don't have a route for multicast traffic. Some systems don't add this by default, and you need to run.
route add -net 224.0.0.0 netmask 224.0.0.0 eth0(or similar). If you wish to use RAT in unicast mode only, it is possible to add the multicast route on the loopback interface.
“IP_ADD_MEMBERSHIP:没有这样的设备”是什么意思?
这意味着该工具正在尝试使用多播,但网络接口不支持它有两个可能的原因:
您的机器没有启用多播支持。例如,在 Linux 和 FreeBSD 上,可以编译不支持多播的内核。
您没有用于多播流量的路由。有的系统默认不加这个,需要运行。
route add -net 224.0.0.0 netmask 224.0.0.0 eth0(或类似)。如果您只想在单播模式下使用 RAT,则可以在环回接口上添加组播路由。
回答by Steve-o
IP_ADD_MEMBERSHIPand bind()are only required for receiving multicast, use IP_MULTICAST_IFinstead for effectively a "send-only membership" of a multicast group.
IP_ADD_MEMBERSHIP并且bind()仅在接收多播时才需要,IP_MULTICAST_IF而是用于有效地作为多播组的“仅发送成员资格”。
IP_MULTICAST_IFsets the kernel to send multicast packets for a given group on a given interface, it is effectively "send-only" as you will not be able to receive traffic on that group after setting. This varies by platform: Posix platforms generally function this way as an optimisation, whilst Win32 will perform software level routing to propagate locally generated packets.
IP_MULTICAST_IF将内核设置为在给定接口上为给定组发送多播数据包,它实际上是“仅发送”,因为设置后您将无法接收该组上的流量。这因平台而异:Posix 平台通常以这种方式进行优化,而 Win32 将执行软件级路由以传播本地生成的数据包。

