2017-07-06 89 views
0

下面有兩個Groovy子程序通過普通的UDP套接字向對方發送消息。當他們發送到127.0.0.1時,他們確實收到消息。但是,將消息發送到公共IP地址時(該機器位於NAT後面)未收到消息。爲什麼UDP打孔不能用於公共IP地址?

爲什麼不打孔?以及如何解決這個問題?

我試過早期通過Java庫查詢公共STUN服務器,但它使用相同的公共IP地址給我回應,所以我在這裏使用wtfismyip.com

class GroovyTest { 

static String PUBLIC_IP = new URL('https://wtfismyip.com/text').text.trim() 
//static String PUBLIC_IP = '127.0.0.1' // works fine 

static void main(String[] args) { 
    runInstance(11111, 22222) 
    runInstance(22222, 11111) 
} 

static void runInstance(int thisPort, int anotherPort) { 
    def socket = new DatagramSocket(thisPort) 
    Thread.start { 
     // message listener 
     byte[] buf = new byte[1024] 
     while (true) { 
      DatagramPacket packet = new DatagramPacket(buf, buf.length); 
      socket.receive(packet); 
      InetAddress remoteAddr = packet.getAddress(); 
      int remotePort = packet.getPort(); 
      String sentence = new String(packet.getData(), 0, packet.length); 
      println("server-$thisPort: received [$sentence] from ${remoteAddr.hostAddress}:${remotePort}") 
     } 
    } 
    Thread.start { 
     // message sender 
     while (true) { 
      println("client-$thisPort: sending to ${PUBLIC_IP}:${anotherPort}...") 
      byte[] buf = ("Hello " + System.currentTimeMillis()).bytes 
      DatagramPacket packet = new DatagramPacket(buf, buf.length, InetAddress.getByName(PUBLIC_IP), anotherPort) 
      socket.send(packet) 
      Thread.sleep(2000) 
     } 
    } 
} 

} 
+2

'new URL('https://wtfismyip.com/text').text.trim()' - 真的嗎? –

+0

@shmosel哦Groovy –

+1

https://stackoverflow.com/a/8524609/104458 – selbie

回答

0

您的問題,從一個事實,即wtfismyip返回的IP地址是您的網絡,這是不分配給您的計算機上的路由器的IP地址造成的。當您嘗試將數據報發送到路由器的公用IP時,您可能會收到來自路由器的ICMP目標不可達錯誤消息。如果您需要這種行爲,您的路由器可能具有一些端口轉發功能,可以將入站UDP流量轉發到您的本地IP地址。

0

我已經簡單地從我回應的UDP數據包採取的地址和端口的詳細信息已成功回覆NAT路由器後面的UDP數據包...

DatagramSocket socket = new DatagramSocket(port); 
DatagramPacket receivePacket = new DatagramPacket(receiveBuffer, receiveBuffer.length); 
socket.receive(receivePacket); 

DatagramPacket sendPacket = new DatagramPacket(sendBuffer, sendBuffer.length, 
    receivePacket.getAddress(), receivePacket.getPort()); 
socket.send(sendPacket); 

的代碼是在更穩健這個數據包來自哪裏並不重要,或者一路上發生的任何地址轉換。它會一直回覆正確的地方。

我也注意到你正在使用兩個不同的端口號。 「thisPort」和「anotherPort」。據我所知,如果你在相同的端口號上回復,打孔只能工作。這是安全的原因。

我的頭像上的海洋機器人使用了這種UDP打孔技術。