UDP打孔Java示例 [英] UDP Hole Punching Java Example

查看:139
本文介绍了UDP打孔Java示例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在具有静态IP的服务器的帮助下与两个客户端进行UDP打孔.服务器在端口7070和7071上等待两个客户端.此后,它将彼此发送IP地址和端口.这部分工作正常.但是我无法在两个客户端之间建立通信.我在不同的Wifi网络和3G移动网络中尝试了该代码.客户端程序将引发IO异常没有通往主机的路由". 客户端代码用于两个客户端.使用端口7070执行一次,使用7071执行一次.

I want to do UDP Hole Punching with two clients with the help of a server with a static IP. The server waits for the two clients on port 7070 and 7071. After that it sends the IP address and port to each other. This part is working fine. But I'm not able to establish a communication between the two clients. I tried the code in different Wifi networks and in 3G mobile network. The client program throws the IO-Exception "No route to host". The client code is used for both clients. Once executed with port 7070 and once with 7071.

您认为我正确实现了UDP打孔概念吗?有什么想法可以使它起作用吗? 这是服务器代码,其次是客户端代码.

Do you think I've implemented the UDP hole punching concept correctly? Any ideas to make it work? Here's the server code first, followed by the client code.

感谢您的帮助.

服务器代码:

public class UDPHolePunchingServer {

    public static void main(String args[]) throws Exception {

    // Waiting for Connection of Client1 on Port 7070
    // ////////////////////////////////////////////////

    // open serverSocket on Port 7070
    DatagramSocket serverSocket1 = new DatagramSocket(7070);

    System.out.println("Waiting for Client 1 on Port "
            + serverSocket1.getLocalPort());

    // receive Data
    DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
    serverSocket1.receive(receivePacket);

    // Get IP-Address and Port of Client1
    InetAddress IPAddress1 = receivePacket.getAddress();
    int port1 = receivePacket.getPort();
    String msgInfoOfClient1 = IPAddress1 + "-" + port1 + "-";

    System.out.println("Client1: " + msgInfoOfClient1);

    // Waiting for Connection of Client2 on Port 7071
    // ////////////////////////////////////////////////

    // open serverSocket on Port 7071
    DatagramSocket serverSocket2 = new DatagramSocket(7071);

    System.out.println("Waiting for Client 2 on Port "
            + serverSocket2.getLocalPort());

    // receive Data
    receivePacket = new DatagramPacket(new byte[1024], 1024);
    serverSocket2.receive(receivePacket);

    // GetIP-Address and Port of Client1
    InetAddress IPAddress2 = receivePacket.getAddress();
    int port2 = receivePacket.getPort();
    String msgInfoOfClient2 = IPAddress2 + "-" + port2 + "-";

    System.out.println("Client2:" + msgInfoOfClient2);

    // Send the Information to the other Client
    // /////////////////////////////////////////////////

    // Send Information of Client2 to Client1
    serverSocket1.send(new DatagramPacket(msgInfoOfClient2.getBytes(),
            msgInfoOfClient2.getBytes().length, IPAddress1, port1));

    // Send Infos of Client1 to Client2
    serverSocket2.send(new DatagramPacket(msgInfoOfClient1.getBytes(),
            msgInfoOfClient1.getBytes().length, IPAddress2, port2));

    //close Sockets
    serverSocket1.close();
    serverSocket2.close();
}

客户代码

public class UDPHolePunchingClient {

    public static void main(String[] args) throws Exception {
    // prepare Socket
    DatagramSocket clientSocket = new DatagramSocket();

    // prepare Data
    byte[] sendData = "Hello".getBytes();

    // send Data to Server with fix IP (X.X.X.X)
    // Client1 uses port 7070, Client2 uses port 7071
    DatagramPacket sendPacket = new DatagramPacket(sendData,
            sendData.length, InetAddress.getByName("X.X.X.X"), 7070);
    clientSocket.send(sendPacket);

    // receive Data ==> Format:"<IP of other Client>-<Port of other Client>"
    DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
    clientSocket.receive(receivePacket);

    // Convert Response to IP and Port
    String response = new String(receivePacket.getData());
    String[] splitResponse = response.split("-");
    InetAddress ip = InetAddress.getByName(splitResponse[0].substring(1));

    int port = Integer.parseInt(splitResponse[1]);

    // output converted Data for check
    System.out.println("IP: " + ip + " PORT: " + port);

    // close socket and open new socket with SAME localport
    int localPort = clientSocket.getLocalPort();
    clientSocket.close();
    clientSocket = new DatagramSocket(localPort);

    // set Timeout for receiving Data
    clientSocket.setSoTimeout(1000);

    // send 5000 Messages for testing
    for (int i = 0; i < 5000; i++) {

        // send Message to other client
        sendData = ("Datapacket(" + i + ")").getBytes();
        sendPacket = new DatagramPacket(sendData, sendData.length, ip, port);
        clientSocket.send(sendPacket);

        // receive Message from other client
        try {
            receivePacket.setData(new byte[1024]);
            clientSocket.receive(receivePacket);
            System.out.println("REC: "
                    + new String(receivePacket.getData()));

        } catch (Exception e) {
            System.out.println("SERVER TIMED OUT");
        }
    }

    // close connection
    clientSocket.close();
}

更新 该代码通常可以正常工作.我已经在两个不同的家庭网络中进行了尝试,并且可以正常工作.但这不适用于我的3G或大学网络.在3G中,即使关闭和打开clientSocket,我也验证了NAT是否再次将两个端口(客户端端口和由路由器分配的端口)映射在一起.有谁知道为什么它不起作用?

UPDATE The code is generally working. I've tried it in two different home networks now and it's working. But it isn't working in my 3G or university network. In 3G, I verified that the NAT is mapping the two ports (the client port and by the router assigned port) together again, even after closing and opening the clientSocket. Has anyone an idea why it isn't working then?

推荐答案

并非所有类型的NAT都能实现UDP打孔.没有为所有类型的NAT定义通用或可靠的方法.对称NAT甚至非常困难.

UDP hole punching can't be achieved with all types of NAT. There is no universal or reliable way defined for all types of NAT. It is even very difficult for symmetric NAT.

根据NAT行为,对于发送UDP数据包的不同设备,端口映射可能会有所不同. 像,如果A向B发送UDP数据包,则可能会获得50000等端口.但是,如果A向C发送UDP数据包,则可能会获得50002等不同的映射.因此,在您的情况下,向服务器发送数据包可能给客户端一个端口,但是向另一个客户端发送数据包可能会给其他端口.

Depending on the NAT behaviour, the port mapping could be different for different devices sending the UDP packets. Like, If A sends a UDP packet to B, it may get some port like 50000. But if A sends a UDP packet to C, then it may get a different mapping like 50002. So, in your case sending a packet to server may give a client some port but sending a packet to other client may give some other port.

您应在此处阅读有关NAT行为的更多信息:

You shall read more about NAT behaviour here:

http://tools.ietf.org/html/rfc4787

https://tools.ietf.org/html/rfc5128

3G上的UDP打孔没有通过

这篇关于UDP打孔Java示例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆