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

来源:互联网 发布:java基础教程 免费下载 编辑:程序博客网 时间:2024/04/30 17:07

参考博文:
解决接收不到组播包的问题 - Justlinux2010的专栏 - 博客频道 - CSDN.NET
http://blog.csdn.net/justlinux2010/article/details/11140383

1、问题描述
实现在多网卡设备上发送组播消息,实现设备搜索,并接收通过组播返回的搜索信息。
设备为多网卡nvr,有一个常规网卡和一个PPPOE口;在进行发送组播搜索ipc时,只可以在常规网卡上接收到反馈的组播信息,而在ppoe上没有
2、问题原因及解决方法

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

    int CreateMuticastSocket(const std::string &ethx, 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、在多网卡实现多播(如设备搜索)相关的功能时,可以针对多个网卡分别执行一次操作,同时可以区分设备是从哪个网卡搜索到的。

0 0
原创粉丝点击