java - 如何在不同网络的 NAT 后面的两个客户端之间建立 TCP 连接?

标签 java hole-punching

我有一个设置,其中 2 个(假设 A 和 B)位于每个公共(public) IP 的 NAT 后面。所以他们各自有自己不同的私有(private)IP。我在两者之间使用服务器,它将交换 IP 地址和端口号。 A 和 B。他们还交换他们的内部端口号..!

enter image description here

基本上这就是设置。

客户端A和B运行以下代码:

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class Clientnew {

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

    for(int i = 1;i<10;i++){
    // prepare Data
    byte[] sendData = "Hello".getBytes();
    // send Data to Serverc
    DatagramPacket sendPacket = new DatagramPacket(sendData,
            sendData.length, InetAddress.getByName("27.251.62.27"), 7070);
    clientSocket.send(sendPacket);

    //send localip and local port to server
         System.out.println("Sending Local info");
//   InetAddress IPAddressLocal = clientSocket.getLocalAddress();
   int PortLocal = clientSocket.getLocalPort();
        String msgInfoOfClient1 = PortLocal+":PortLocal";

        byte[] newData = msgInfoOfClient1.getBytes();
         System.out.println(msgInfoOfClient1);
        DatagramPacket sendLocalPacket = new DatagramPacket(newData, newData.length, InetAddress.getByName("27.251.62.27"), 7070);
        clientSocket.send(sendLocalPacket);

     // receive External Data ==> Format:"<External IP of other Client>-<External 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 External_IP = InetAddress.getByName(splitResponse[0].substring(1));

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

    // output converted Data for check
    System.out.println("External IP: " + External_IP + " External PORT: " + External_Port);   


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

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

    int Internal_Port = Integer.parseInt(splitResponse[0]);

    // output converted Data for check
    System.out.println(" Internal PORT: " + Internal_Port);   
    }
     }
}

服务器S上的代码是:-

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

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

        DatagramSocket serverSocket2 = new DatagramSocket(6588);
        // Waiting for Connection of Client1 on Port 7070
        // ////////////////////////////////////////////////

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

        for(int i= 1; i<10;i++){

        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 FirstmsgInfoOfClient1 = IPAddress1 + "-" + port1 + "-";

        System.out.println("Client1 External: " + FirstmsgInfoOfClient1);

        // Get Message from Client
        DatagramPacket anotherPacket = new DatagramPacket(new byte[1024], 1024);
        serverSocket1.receive(anotherPacket);

        // Decode the String
        String response = new String(anotherPacket.getData());
        String[] splitResponse = response.split(":");
//        InetAddress LocalIP1 = InetAddress.getByName(splitResponse[0].substring(1));
        int LocalPort1 = Integer.parseInt(splitResponse[0]);
//        int LocalPort1 = Integer.parseInt(splitResponse[1]);
//        String msgInfoOfClient1 = PortLocal+":PortLocal";
        String SecondmsgInfoOfClient1 = LocalPort1+":LocalPort1";

        System.out.println("Client1 Internal: " + SecondmsgInfoOfClient1);
//        System.out.println(response);



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

        // open serverSocket on Port 6588

//         DatagramSocket serverSocket2 = new DatagramSocket(6588);

        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 FirstmsgInfoOfClient2 = IPAddress2 + "-" + port2 + "-";

        System.out.println("Client2 External:" + FirstmsgInfoOfClient2);

         // Get Message from Client
        anotherPacket = new DatagramPacket(new byte[1024], 1024);
        serverSocket2.receive(anotherPacket);

        // Decode the String

        response = new String(anotherPacket.getData());
        splitResponse = response.split(":");
//        InetAddress LocalIP1 = InetAddress.getByName(splitResponse[0].substring(1));
        int LocalPort2 = Integer.parseInt(splitResponse[0]);
//        int LocalPort1 = Integer.parseInt(splitResponse[1]);
//        
        String SecondmsgInfoOfClient2 = LocalPort2+":LocalPort2";

        System.out.println("Client2 Internal: " + SecondmsgInfoOfClient2);

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

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

        serverSocket1.send(new DatagramPacket(SecondmsgInfoOfClient2.getBytes(), 
                SecondmsgInfoOfClient2.getBytes().length, IPAddress1, port1));


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

        serverSocket2.send(new DatagramPacket(SecondmsgInfoOfClient1.getBytes(), 
                SecondmsgInfoOfClient1.getBytes().length, IPAddress2, port2));

            System.out.println("-----------------\n");
            System.out.println("---------------------");
        }

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

输出是他们正在很好地交换内部和外部端口以及公共(public) IP。

所以问题是如何使用此信息在 A 和 B 之间打开 TCP 连接?如何使用 Java 实现 TCP Punch hole?

P.S: 必须是TCP连接,我用的是Java。

最佳答案

在 S 上打开两个 ServerSocket,分别接受来自 A 和 B 的连接(分别是端口 62000 和 31000)。当 accept 在每种情况下返回一个 Socket 实例然后将每个实例的 InputStreamOutputStream 交叉使用PipedOutputStreamPipedInputStream。每个人都需要一个线程。

关于java - 如何在不同网络的 NAT 后面的两个客户端之间建立 TCP 连接?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31536740/

相关文章:

networking - 如何模拟不同的NAT行为

java - 无法找到或加载主类 Foo

caching - 尝试通过 Magento 的整页缓存来打洞动态内容

c# - UDP 打洞问题

java - JNLP 文件的本地替代方案?

sockets - 如何进行 TCP 打洞?

sockets - UDP打洞算法

java - 来 self 的 Android 应用程序的蓝牙设备上的音频闪烁

java - setAdapter() 上的 NullPointer 异常

java - Spring 如何通知实例何时被销毁?