2017-07-06 4 views
0

Il existe deux sous-programmes Groovy ci-dessous qui envoient des messages les uns aux autres via des sockets UDP simples. Ils reçoivent les messages avec succès lorsqu'ils sont envoyés au 127.0.0.1. Mais les messages ne sont pas reçus lors de leur envoi à l'adresse IP publique (la machine est derrière NAT).Pourquoi la perforation UDP ne fonctionne pas pour l'adresse IP publique?

Pourquoi le trou n'est pas perforé? Et comment réparer ça?

J'ai essayé d'interroger un serveur public STUN via une bibliothèque Java plus tôt, mais il a répondu avec la même adresse IP publique, donc j'utilise wtfismyip.com ici.

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

'nouvelle URL ('https://wtfismyip.com/text') .text.trim()' - vraiment? –

+0

@shmosel Oh Groovy –

+1

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

Répondre

0

Votre problème découle du fait que l'adresse IP renvoyée par wtfismyip est l'adresse IP du routeur sur votre réseau, qui n'est pas attribué à votre ordinateur. Lorsque vous essayez d'envoyer un datagramme à l'adresse IP publique de votre routeur, vous obtenez probablement le message d'erreur ICMP Destination Unreachable de votre routeur. Si vous avez besoin de ce comportement, votre routeur peut disposer de capacités de transfert de port pouvant acheminer le trafic UDP entrant vers votre adresse IP locale.

0

J'ai répondais avec succès aux paquets UDP derrière un routeur NAT en prenant simplement les détails d'adresse et le port du paquet UDP je réponds à ...

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); 

Le code est plus robuste que peu importe d'où vient le paquet ou toute traduction d'adresse qui s'est produite en cours de route. Il répondra toujours au bon endroit.

J'ai également remarqué que vous utilisez deux numéros de port différents. "thisPort" et "anotherPort". Autant que je sache, la perforation ne fonctionnera que si vous répondez sur le même numéro de port. Cela a du sens pour des raisons de sécurité.

Le robot marin sur le dessus de ma tête, photographié dans mon avatar, utilise cette technique de perforation UDP.