您的位置:首页 > 运维架构 > Linux

linux 在多网卡下的设备的UDP 组播问题总结

2016-09-15 18:33 1586 查看
参考博文:

解决接收不到组播包的问题 - Justlinux2010的专栏 - 博客频道 - CSDN.NET

http://blog.csdn.net/justlinux2010/article/details/11140383

1、问题描述

实现在多网卡设备上发送组播消息,实现设备搜索,并接收通过组播返回的搜索信息。

设备为多网卡nvr,有一个常规网卡和一个PPPOE口;在进行发送组播搜索ipc时,只可以在常规网卡上接收到反馈的组播信息,而在ppoe上没有

2、问题原因及解决方法

关键代码(组播socket的初始化):

int CreateMuticastSocket(const std::string ðx, int port)
{
int ret = 0;
int sockfd = socket(AF_INET,SOCK_DGRAM,0);
if(-1 == sockfd)
{
printf("socket error!!!\n");
perror("socket:");
return -1;
}

/*test ip*/
struct sockaddr_in localaddr = {0};
localaddr.sin_family = AF_INET;
localaddr.sin_port = htons(port);
localaddr.sin_addr.s_addr = htonl(INADDR_ANY);
ret = bind(sockfd,(struct sockaddr*)&localaddr,sizeof(struct sockaddr));
if(-1 == ret)
{
printf("bind localaddr error!!!\n");
perror("bind:");
close(sockfd);
return -1;
}
int reuse = 1;
if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0)
{
perror("Setting SO_REUSEADDR error");
close(sockfd);
return -1;
}
/*设置是否支持本地回环接收*/
int loopBack=1;
ret = setsockopt(sockfd,IPPROTO_IP, IP_MULTICAST_LOOP, &loopBack, sizeof(loopBack));
if(-1 == ret)
{
printf("setsockopt broadcaset error!!!\n");
perror("setsockopt:");
close(sockfd);
return -1;
}

/*
将本地socket添加到多播组中,注意,此处针对struct ip_mreq结构体需要填充两个成员,
成员ipmr.imr_interface.s_addr的值指定的是将要发送的网卡的ip地址,
成员impr.imr_multiaddr指定的是组播地址;
如果指定为INADDR_ANY则系统会绑定一个默认网卡的具体ip(根据默认网关选择),则会出现特定网卡可以发送和接收组播信息,另一网卡不可以。即指定INADDR_ANY并不能把所有网卡都添加多播组中,必须明确指定对应网卡ip才可以。*/
struct in_addr addr = {0};
addr.s_addr=inet_addr(get_local_ip(ethx).c_str());
struct ip_mreq ipmr;
ipmr.imr_interface.s_addr = addr.s_addr;
ipmr.imr_multiaddr.s_addr = inet_addr(CONST_MULTICAST_IP_V4);
ret=setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,(const char*)&ipmr,sizeof(ipmr));

/*此处指定组播数据的出口网卡,如果不设置则会根据路由表指定默认路由出口*/

if(-1 == setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_IF, (char *)&addr, sizeof(addr)))
{
printf("set error IP_MULTICAST_IF %s\n", ethx.c_str());
perror("Setting IP_MULTICAST_IF error:");
close(sockfd);
sockfd = -1;
}

struct timeval tv;
tv.tv_sec = 2;
tv.tv_usec = 0;
ret = setsockopt(sockfd,SOL_SOCKET,SO_RCVTIMEO,(char*)&tv,sizeof(tv));
if(-1 == ret)
{
printf("setsockopt recvtimeout error!!!\n");
perror("setsockopt:");
close(sockfd);
return -1;
}
return sockfd;
}


3、综述

在多网卡设备上实现组播需要特别注意:

1、使用setsockopt设置IP_ADD_MEMBERSHIP组播地址时,对应的本地地址必须被明确指定为要发送组播数据包的网卡的ip地址,而不可以使用INADDR_ANY设置;如果使用INADDR_ANY,则系统会默认根据路由表绑定一个明确的地址,则在接收组播信息时,无法从发送的网卡处接收到数据,发送的网卡没有被添加到组播组中。

2、必须使用setsockopt设置IP_MULTICAST_IF选项,从而修改默认的组播出口网卡。否则系统根据路由表发送到默认网关。而不一定是指定的网卡。

3、在多网卡实现多播(如设备搜索)相关的功能时,可以针对多个网卡分别执行一次操作,同时可以区分设备是从哪个网卡搜索到的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息