我有一个设置,其中2个pc(假设A和B)在每个公共IP的NAT后面。所以他们每个人都有自己不同的私有IP。我在中间使用服务器,它将交换IP地址和端口号。他们还交换了他们的内部港口号。!
所以基本上这就是设置。
客户端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来实现这一点。
答案 0 :(得分:0)
在S上打开两个ServerSocket
,接受来自A和B(分别为端口62000和31000)的连接。当accept
在每种情况下返回Socket
个实例时,请使用InputStream
和OutputStream
将每个实例的PipedOutputStream
和PipedInputStream
相互交叉。你需要为每个人都有一个主题。