繁体   English   中英

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

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

  1. 以管理员身份打开cmd

  2. 输入 ipconfig

  3. 复制我的适配器的 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.

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