为什么UDP打孔不适用于公共IP地址?

时间:2017-07-06 02:02:12

标签: java groovy udp stun

下面有两个Groovy子程序通过普通UDP套接字相互发送消息。它们在发送到127.0.0.1时会成功收到消息。但是当将它们发送到公共IP地址(机器在NAT后面)时,不会收到消息。

为什么洞没被打孔?以及如何解决这个问题?

我之前尝试通过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 个答案:

答案 0 :(得分:0)

您的问题源于以下事实:wtfismyip返回的IP地址是网络上路由器的IP地址,该地址未分配给您的计算机。当您尝试将数据报发送到路由器的公共IP时,您可能会从路由器获取ICMP目标无法访问错误消息。如果您需要此行为,您的路由器可能具有一些端口转发功能,可以将入站UDP流量转发到您的本地IP地址。

答案 1 :(得分:0)

我已成功回复NAT路由器后面的UDP数据包,只需从我正在响应的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打孔技术。