[英]DatagramChannel does not receive multicast packets when either the server or client is bound to local IPV4 address
这是服务器
public static void main(String[] args)throws Exception
{
try(DatagramChannel server=DatagramChannel.open())
{
server.bind(new InetSocketAddress("192.168.1.5",5000));
//Receive from any address
ByteBuffer buffer=ByteBuffer.allocate(10);
InetSocketAddress addr=(InetSocketAddress)server.receive(buffer);
buffer.flip();
//print data
byte[] data=new byte[buffer.remaining()];
buffer.get(data);
System.out.println(addr+"/"+new String(data));
//Send back to client address
server.send(ByteBuffer.wrap("World".getBytes()),addr);
}
}
这是客户
public static void main(String[] args)throws Exception
{
//open with IPV4 Protocol
try(DatagramChannel client=DatagramChannel.open(StandardProtocolFamily.INET))
{
//Send to any address
client.send(ByteBuffer.wrap("Hello".getBytes()),new InetSocketAddress("192.168.1.5",5000));
//Receive from any address
ByteBuffer buffer=ByteBuffer.allocate(10);
InetSocketAddress addr=(InetSocketAddress)client.receive(buffer);
buffer.flip();
//print data
byte[] data=new byte[buffer.remaining()];
buffer.get(data);
System.out.println(addr+"/"+new String(data));
}
}
我首先运行服务器,然后将客户端作为 2 个不同 JVM 中的 2 个单独进程运行
地址“192.168.1.5”是我在 Windows 10 上获得的 PC IPV4 地址
以管理员身份打开cmd
输入 ipconfig
复制我的适配器的 IPV4 地址
一切正常
Server Output : /192.168.1.5:64640/Hello
Client Output : /192.168.1.5:5000/World
所以我假设地址 192.168.1.5 正在工作
现在我想对多播套接字执行相同的测试
这是服务器
public static void main(String[] args)throws Exception
{
try(DatagramChannel server=DatagramChannel.open(StandardProtocolFamily.INET))
{
//Not mandatory using only for debugging
server.bind(new InetSocketAddress(5000));
//set it to broadcast on specific adapter
server.setOption(StandardSocketOptions.IP_MULTICAST_IF,supportMulticast());
//send to an specific multi cast address
server.send(ByteBuffer.wrap("OK".getBytes()),new InetSocketAddress("224.0.0.1",7000));
}
}
这是获取第一个支持的多播接口的代码
private static NetworkInterface supportMulticast()throws Exception
{
Enumeration<NetworkInterface> netInterfaces=NetworkInterface.getNetworkInterfaces();
while(netInterfaces.hasMoreElements())
{
NetworkInterface netInterface=netInterfaces.nextElement();
if(!netInterface.isLoopback() || !netInterface.isUp()){continue;}
if(netInterface.supportsMulticast()){return netInterface;}
}
return null;
}
这是客户
public static void main(String[] args)throws Exception
{
try(DatagramChannel client=DatagramChannel.open(StandardProtocolFamily.INET))
{
//allow multiple clients to reuse the below bounded address to allow multiple members on that same address
client.setOption(StandardSocketOptions.SO_REUSEADDR,true);
//must be bound to an local address and match the port of the sender send() address
client.bind(new InetSocketAddress(7000));
//not source specific i.e does not block any specific addresses
MembershipKey key=client.join(InetAddress.getByName("224.0.0.1"),supportMulticast());
//read the data
ByteBuffer buffer=ByteBuffer.allocate(10);
System.out.println("RECEIVED FROM="+client.receive(buffer));
buffer.flip();
System.out.println("MSG="+new String(buffer.array(),0,buffer.limit()));
//leave the group
key.drop();
}
}
我首先运行客户端,然后将服务器作为 2 个单独的进程 [单独的 JVM],我在客户端得到预期的输出
RECEIVED FROM=/127.0.0.1:5000
MSG=OK
到目前为止一切顺利,直到我从这里更改服务器端的绑定方法
server.bind(new InetSocketAddress(5000));
对此
server.bind(new InetSocketAddress("192.168.1.5",5000));
然后客户端没有收到任何数据包并永远挂起
如果我不更改服务器代码,而是让客户端绑定到地址 192.168.1.5,那么客户端再次没有收到任何数据包并永远挂起。
Wire Shark 确认数据包已发送
本地 IPV4 地址 192.168.1.5 适用于常规 DatagramChannel,但不适用于多播组。 知道发生了什么吗?
所以答案是在我的服务器发送数据包的适配器和客户端用来加入组的适配器中
在这个方法中
private static NetworkInterface supportMulticast()throws Exception
{
Enumeration<NetworkInterface> netInterfaces=NetworkInterface.getNetworkInterfaces();
while(netInterfaces.hasMoreElements())
{
NetworkInterface netInterface=netInterfaces.nextElement();
if(!netInterface.isLoopback() || !netInterface.isUp()){continue;}
if(netInterface.supportsMulticast()){return netInterface;}
}
return null;
}
这条线
if(!netInterface.isLoopback() || !netInterface.isUp()){continue;}
将只允许返回支持多播的 Loopback[即 localhost] 适配器。 本地主机适配器只能在本地主机内发送/接收数据包,而不能在本地主机外发送/接收数据包。 我需要的是完全相反的适配器,所以我把它改成了这个
//skip loop back adapter & adapters which are not working
if(netInterface.isLoopback() || !netInterface.isUp()){continue;}
这将返回接口地址为 192.168.1.5 的适配器,现在一切正常
此外,经过更多研究以允许数据包到达特定范围和更远距离之外,我们需要为发送的多播数据包设置 TTL
/*
0->Node Local
1->Link Local
1->32=Site Local
32->64=Region Local
64->255=Global
For sending packets outside localhost
*/
server.setOption(StandardSocketOptions.IP_MULTICAST_TTL,0);
0 对我的情况来说已经足够了
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.