2017-07-06 57 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打孔技术。