-
首先,指定源组播,linux 和windows编程稍微有些不同:
Linux:bind的是组播地址和组播端口
windows:bind的是接收网卡的地址(local_ip)和组播端口
-
对于一个网卡收流,其他网卡不用收流
现象1):组播收不到流。
原因:标红的语句填写的IP地址是any了,如果默认IP不是要收组播的网卡IP,就会收不到流。
解决方法:把srcMreq.imr_interface.s_addr 改成本地IP,即可收到流。
struct ip_mreq_source srcMreq;
srcMreq.imr_multiaddr.s_addr = inet_addr(muticast_ip.c_str());//组播地址
srcMreq.imr_interface.s_addr = inet_addr(local_ip.c_str());//本地网卡的地址
srcMreq.imr_sourceaddr.s_addr = inet_addr(src_ip.c_str());//组播的指定源地址
if (0 > setsockopt(h_sock, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, (char*)&srcMreq, sizeof(srcMreq)))
{
cout << "setsockopt IP_ADD_SOURCE_MEMBERSHIP failed, ";
return false;
}
现象2) :可以收到组播流,但是接收一段时间,就收不到了。时间一般是路由器配置查询器的时间的2倍。
原因:网卡未添加组播路由,所以没有持续发IGMP包,所以路由器查询后,发现没有端口收流,就不继续往端口发流了
解决方法:route add -net 0.0.0.0 netmask 0.0.0.0 dev eth0
-
其次:对于要多网卡收流
现象描述:
网卡1(192.168.100.71) :可以收到组播地址的流(source 192.168.100.150);网卡2(192.168.1.171):收不到组播地址的流(source 192.168.100.150)
原因: 网卡2发送不了IGMP的包,原因1.171不知道里没有100.150的路由,所以不知道往哪里发送,解决方法:route add -net 192.168.100.150 netmask 255.255.255.255 dev enp1s0f2,这样网卡2可以收到组播包,但是网卡1收不到组播包了。
因此要想多网卡都接收组播流,配置路由就不行了。
我还尝试了 sysctl -w net.ipv4.conf.all.rp_filter=2,当把所有网卡的的内核参数都设置2后,网卡enp1s0f2可以收到流了,但是收一段时间后,流就停了,用tcpdump -i enp1s0f2 igmp -l -n -vv 观察,enp1s0f2仅仅收到交换机发送的igmp查询包,却没有enp1s0f2发送的IGMP的包(只有刚开始加入组的时候有两个IGMP的包,正常情况应该是加入的时候发送两个IGMP包,然后每隔一段时间,再发送一个IGMP包)。
后来运行下面的命令,就可以多网卡收流:
sysctl -w net.ipv4.conf.all.rp_filter=0
cat /proc/sys/net/ipv4/conf/all/rp_filter
切记:有几个网卡,就要执行几次sysctl -w net.ipv4.conf.网卡名.rp_filter=0,每个网卡执行一下次
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
-
rp_filter参数详细介绍
rp_filter参数有三个值,0、1、2,具体含义:
0:不开启源地址校验。
1:开启严格的反向路径校验。对每个进来的数据包,校验其反向路径是否是最佳路径。如果反向路径不是最佳路径, 则直接丢弃该数据包。
2:开启松散的反向路径校验。对每个进来的数据包,校验其源地址是否可达,即反向路径是否能通(通过任意网口),如果反向路径不同,则直接丢弃该数据包
如上所示,数据包发到了eth1网卡,如果这时候开启了rp_filter参数,并配置为1,则系统会严格校验数据包的反向路径。从路由表中可以看出,返回响应时数据包要从eth0网卡出,即请求数据包进的网卡和响应数据包出的网卡不是同一个网卡,这时候系统会判断该反向路径不是最佳路径,而直接丢弃该请求数据包。(业务进程也收不到该请求数据包)
解决办法:
1.修改路由表,使响应数据包从eth1出,即保证请求数据包进的网卡和响应数据包出的网卡为同一个网卡。
2.关闭rp_filter参数。(注意all和default的参数都要改)
1)修改/etc/sysctl.conf文件,然后sysctl -p刷新到内存。
2)使用sysctl -w直接写入内存:sysctl -w net.ipv4.conf.all.rp_filter=0
3)修改/proc文件系统: echo "0">/proc/sys/net/ipv4/conf/all/rp_filter
rp_filters参数介绍来自https://www.cnblogs.com/lipengxiang2009/p/7446388.html
多网卡收同一个组播流,当rp_filter=0时,每个网卡上收到两份数据
把socket绑定网卡,让socket接收到该网卡的网络包
struct ifreq Ifreq;
strcpy(Ifreq.ifr_name, "eth0"); //这里指定使用那块网卡拉流 参数为网卡名称
if (setsockopt(h_sock, SOL_SOCKET, SO_BINDTODEVICE, (char *)&Ifreq, sizeof(Ifreq)) < 0)
{
perror("setsockopt():SO_BINDTODEVICE");
return false;
}