简体   繁体   English

当服务器或客户端绑定到本地 IPV4 地址时,DatagramChannel 不接收多播数据包

[英]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 地址

  1. opening cmd as administrator以管理员身份打开cmd

  2. typing ipconfig输入 ipconfig

  3. 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM