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

时间:2015-07-21 10:38:30

标签: java hole-punching

我有一个设置,其中2个pc(假设A和B)在每个公共IP的NAT后面。所以他们每个人都有自己不同的私有IP。我在中间使用服务器,它将交换IP地址和端口号。他们还交换了他们的内部港口号。!

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

输出是他们正在完美地交换内部和外部端口和公共IP。

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

P.S:最重要的是成为TCP连接,并且我使用Java来实现这一点。

1 个答案:

答案 0 :(得分:0)

在S上打开两个ServerSocket,接受来自A和B(分别为端口62000和31000)的连接。当accept在每种情况下返回Socket个实例时,请使用InputStreamOutputStream将每个实例的PipedOutputStreamPipedInputStream相互交叉。你需要为每个人都有一个主题。