[英]DatagramChannel does not receive multicast packets when either the server or client is bound to local IPV4 address
This is the server这是服务器
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);
}
}
And this is the client这是客户
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));
}
}
I run the server first then the client as 2 seperate processes in 2 diffrent JVM's我首先运行服务器,然后将客户端作为 2 个不同 JVM 中的 2 个单独进程运行
The Address "192.168.1.5" is my PC IPV4 address which i obtained on windows 10 by地址“192.168.1.5”是我在 Windows 10 上获得的 PC IPV4 地址
opening cmd as administrator以管理员身份打开cmd
typing ipconfig输入 ipconfig
copy the IPV4 address of my adapter复制我的适配器的 IPV4 地址
Everything works fine一切正常
Server Output : /192.168.1.5:64640/Hello
Client Output : /192.168.1.5:5000/World
So i assume the address 192.168.1.5 is working所以我假设地址 192.168.1.5 正在工作
Now i want to perform the same test for multicast sockets现在我想对多播套接字执行相同的测试
Here is the server这是服务器
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));
}
}
Here is the code to get the 1st supported multicast interface这是获取第一个支持的多播接口的代码
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;
}
And here is the client这是客户
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();
}
}
I Run the client first then the server as 2 separate processes[separate JVM's] and i get the expected output on the client side我首先运行客户端,然后将服务器作为 2 个单独的进程 [单独的 JVM],我在客户端得到预期的输出
RECEIVED FROM=/127.0.0.1:5000
MSG=OK
So far so good until i change the bind method on my server side from this到目前为止一切顺利,直到我从这里更改服务器端的绑定方法
server.bind(new InetSocketAddress(5000));
To this对此
server.bind(new InetSocketAddress("192.168.1.5",5000));
Then the client does not receive any packets and hangs forever然后客户端没有收到任何数据包并永远挂起
If i don't alter the server code but instead make the client bind to the address 192.168.1.5 then again the client gets no packets and hangs forever.如果我不更改服务器代码,而是让客户端绑定到地址 192.168.1.5,那么客户端再次没有收到任何数据包并永远挂起。
Wire shark confirms that the packets get sent Wire Shark 确认数据包已发送
The local IPV4 address 192.168.1.5 works for regular DatagramChannels but does not work Multicast groups.本地 IPV4 地址 192.168.1.5 适用于常规 DatagramChannel,但不适用于多播组。 Any idea whats happening?
知道发生了什么吗?
So the answer was in the adapter my server sends packets in and the adapter which the client uses to join the group所以答案是在我的服务器发送数据包的适配器和客户端用来加入组的适配器中
In this method在这个方法中
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;
}
This line这条线
if(!netInterface.isLoopback() || !netInterface.isUp()){continue;}
will only allow an Loopback[ie an localhost] adapter which supports multicast to be returned.将只允许返回支持多播的 Loopback[即 localhost] 适配器。 The Localhost adapter can only send/receive packets within the localhost and not outside it.
本地主机适配器只能在本地主机内发送/接收数据包,而不能在本地主机外发送/接收数据包。 What i need is the adapter which does the exact opposite so i changed it to this
我需要的是完全相反的适配器,所以我把它改成了这个
//skip loop back adapter & adapters which are not working
if(netInterface.isLoopback() || !netInterface.isUp()){continue;}
This returns me the adapter with the interface address 192.168.1.5 and everything works perfectly now这将返回接口地址为 192.168.1.5 的适配器,现在一切正常
Also after a bit more research to allow an packet to reach outside an certain scope and further distances we need to set the TTL for the multicast packets sent此外,经过更多研究以允许数据包到达特定范围和更远距离之外,我们需要为发送的多播数据包设置 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 was enough for my case 0 对我的情况来说已经足够了
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.