簡體   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