我们遇到了一个棘手的问题.我们正在编写一个接收多播UDP流量的c ++程序.我们正在将应用程序迁移到不同的网络环境,我们的运营团队已要求我们支持来自应用程序的IGMPv3会员公告.初步调查表明,Linux 2.6内核确实支持IGMPv3.因此,我很困惑,当我们运行tcpdump时,我们看到以下输出跟踪:
[rtv@myhost]$ sudo /usr/sbin/tcpdump -i eth1.22 igmp
tcpdump: listening on eth1.22
00:20:09.007094 switch-a.stage > ALL-SYSTEMS.MCAST.NET: igmp query v2 [max resp time 20] [ttl 1]
00:20:09.241946 10.129.22.236 > 232.0.1.10: igmp v2 report 232.0.1.10 (DF) [tos 0xc0] [ttl 1]
00:20:10.472159 10.129.22.236 > 236.0.1.101: igmp v2 report 236.0.1.101 (DF) [tos 0xc0] [ttl 1]
44 packets received by filter
Run Code Online (Sandbox Code Playgroud)
我的理解是,通过在文件/proc/sys/net/ipv4/conf/eth1.22/force_igmp_version中指定非零值,可以强制内核使用较低版本的IGMP; 但是,我已经确认该文件的配置值为零.
我们的应用程序使用以下代码加入多播组:
... joinMulticast(in_addr mcast_addr, in_addr interface_addr)
{
struct ip_mreq mcast_req;
mcast_req.imr_multiaddr.s_addr = mcast_addr;
mcast_req.imr_interface.s_addr = interface_addr;
int err = setsockopt(fFileDesc, IPPROTO_IP, …
Run Code Online (Sandbox Code Playgroud) 似乎多播接收在某些Android设备上不起作用.我无法通过13个测试设备中的4个接收多播.在这4个设备上,应用程序似乎不发送加入多播组的IGMP请求.
接收多播的代码如下所示:
WifiManager wifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
WifiManager.WifiLock wifiLock = wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, TAG);
WifiManager.MulticastLock multicastLock = wifiManager.createMulticastLock(TAG);
multicastLock.setReferenceCounted(true);
wifiLock.acquire();
multicastLock.acquire();
try {
MulticastSocket socket = new MulticastSocket(32123);
InetAddress group = InetAddress.getByName("224.1.2.3");
socket.joinGroup(group);
DatagramPacket packet;
byte[] buf = new byte[256];
packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
socket.leaveGroup(group);
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
multicastLock.release();
wifiLock.release();
Run Code Online (Sandbox Code Playgroud)
该应用具有以下权限:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
Run Code Online (Sandbox Code Playgroud)
为了演示这个问题,我在GitHub:MulticastTest上使用上面的代码创建了一个小测试项目.
我的代码有问题吗?我错过了许可吗?
编辑1:此问题似乎与特定的Android版本无关.我可以在Android 4.x,5.x和6.x上重现这种行为.
编辑2:有一个相关的问题.
我在以下场景中遇到IGMP套接字调用错误;
fd = socket(PF_INET, SOCK_RAW, IPPROTO_IGMP) ;
setsockopt( fd, IPPROTO_IP, IP_HDRINCL, nval, sizeof(nval) );
/** Fill in the IP header and Ethernet header**/
/*** Fill, create the IGMP packet structures***/
if(sendto( fd, &buf, sizeof(buf), 0,(struct sockaddr *) &addr, sizeof(addr)) < 0) {
printf("Socket Sendto error %d : %s\n", errno, strerror(errno));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
sendto调用失败说消息太长.我使用8192作为缓冲区大小.所以我尝试使用以下调用来修复此错误;
if(setsockopt(dlpifd, IPPROTO_IP, SO_SNDBUF, &val, sizeof(int)) < 0) {
printf("Can't set socket options:%d:%s\n", errno, strerror(errno));
return 0;`
}
Run Code Online (Sandbox Code Playgroud)
setsockopt()调用成功,但sendto()的错误相同;
所以我用getsockopt()调用检查SO_SNDBUF大小,它显示1个字节?
我在做什么是错的.
Linux内核是否需要重新编译才能获得IGMP支持?或者我错过了什么?
我是 lwip 的新手,我想用 lwip 创建一个多播接收器。我的步骤如下: 1.启用LWIP_IGMP;2、在low_level_init()中设置NETIF_FLAG_IGMP;3、加入组播组,创建并绑定pcb;4. udp_connect到remote_ip(或多播IP地址?都尝试过但失败)
加入组返回成功,当程序执行此操作时,一切看起来都很好。然而组播接收器不工作,没有组播数据进入网络接口。看来我实际上并没有将我的接收者加入到 igmp 组,尽管加入过程看起来不错。有人知道我错过了什么吗?
我在igmp_joingroup()中发现“netif->igmp_mac_filter != NULL”,但是这个回调被设置为NULL并且没有实现。我是否需要自己实现来设置 MAC 过滤器,或者将其保留为 NULL 就可以了?
非常感谢你的帮助!
瑞安
我需要在主机上的所有可用地址上发送相同的多播UDP数据包.我需要发送到localhost
/ 127.0.0.1
和239.255.0.1
.std
从版本1.2开始,Rust的lib已经弃用了多播行为,无论如何,为了获得我需要的特性,我必须切换到更完整的行为net2
.
该net2
API有一堆的UDP扩展其提供我正在寻找的API.我特别感兴趣
fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> Result<()>
Run Code Online (Sandbox Code Playgroud)
但我无法弄清楚如何处理multiaddr vs interface.我以为我会给multiaddr 127.0.0.1
或者239.255.0.1
如何找到interface
参数的有效IPv4 ?有一个Rust函数,在某个地方,可以提供一个Vec<Ipv4Addr>
?我需要解析输出ifconfig
吗?
这是一个独立的程序,它发出我的公共接口(必须192.168.0.102
手动找到该地址):
extern crate net2;
use std::net::{ UdpSocket, Ipv4Addr };
use net2::UdpSocketExt;
fn main() {
let sock = UdpSocket::bind("0.0.0.0:2345").unwrap();
let local_addr = Ipv4Addr::new(192, 168, 0, 102);
let multicast_addr = Ipv4Addr::new(239, 255, 0, 1);
sock.join_multicast_v4(&multicast_addr, &local_addr).unwrap();
}
Run Code Online (Sandbox Code Playgroud)
如果这有任何区别,我正在编制夜莺.
我正在编写一些使用 IGMP 加入多播组的代码
struct ip_mreq mreq;
inet_pton(AF_INET, group, &mreq.imr_multiaddr.s_addr);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char*)&mreq, sizeof(mreq)) < 0)
throw std::runtime_error(perror("setsockopt(IP_ADD_MEMBERSHIP)"));
Run Code Online (Sandbox Code Playgroud)
当应用程序关闭时,它关闭套接字
close(fd);
Run Code Online (Sandbox Code Playgroud)
但是,它不执行IP_DROP_MEMBERSHIP
.
我们有一个C#应用程序,可以加入和接收来自多播组的数据.这很好用.我们现在想要支持IGMPv3并且能够在加入多播组时指定源的IP.从MSDN文档中,我看不到如何执行此操作.我发现以下链接似乎回答了我的问题.
http://social.msdn.microsoft.com/Forums/en/netfxnetcom/thread/e8063f6d-22f5-445e-a00c-bf46b46c1561
这是我实现这个的方式:
byte[] membershipAddresses = new byte[12]; // 3 IPs * 4 bytes (IPv4)
Buffer.BlockCopy(multicastIp.GetAddressBytes(), 0, membershipAddresses, 0, 4);
Buffer.BlockCopy(sourceIp.GetAddressBytes(), 0, membershipAddresses, 4, 4);
Buffer.BlockCopy(localIp.GetAddressBytes(), 0, membershipAddresses, 8, 4);
socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, membershipAddresses);
Run Code Online (Sandbox Code Playgroud)
但是当我用这个错误调用SetSocketOption()时,我得到一个SocketException : The requested address is not valid in its context
.
有人能指出我在这里做错了吗?谢谢!
我已经嗅探了一个IGMP数据包,现在我想在python的帮助下发送它。有什么办法可以发送像
0x0000 01 00 5E 00 43 67 00 02-B3 C8 7F 44 81 00 00 DE ..^.Cg..??D?..?
0x0010 08 00 46 00 00 20 00 01-00 00 01 02 36 4C C0 A8 ..F.. ......6L??
0x0020 00 7B EA 00 43 67 94 04-00 00 16 00 BC 97 EA 00 .{?.Cg”.....?—?.
0x0030 43 67 Cg
Run Code Online (Sandbox Code Playgroud)
没有像流浪者这样的数据包生成器?
UPD好吧,我尝试使用原始套接字,如下所示:
dst = '234.0.67.103'
# Open a raw socket.
s = socket.socket(socket.AF_INET, socket.SOCK_RAW,2)
res=''
temp='01 00 5E 00 43 67 00 02 …
Run Code Online (Sandbox Code Playgroud)