TCP打孔Java示例

TCP打孔Java示例,java,sockets,tcp,bind,hole-punching,Java,Sockets,Tcp,Bind,Hole Punching,我正在本地计算机上使用以下代码: import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; import java.net.InetSocketAddress; import java.net.Serv

我正在本地计算机上使用以下代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * Just for testing socket SO_RESUEADDR. If set SO_RESUEADDR to true, we can use
 * a single local port to listen for incoming TCP connections, and to initiate
 * multiple outgoing TCP connections concurrently. By this way we can implement
 * TCP hole punching(establish P2P connection traversal through NAT over TCP).
 */
public class TcpPeer2 {
// TCP port is a different source from UDP port, it means you can listen on
// same port for both TCP and UDP at the same time.
private int localport = 7890;
private ServerSocket peerSock;
private Socket serverSocket;

public TcpPeer2(final String serverHost, final int serverPort, final int localPort)
       throws Exception {
 this.localport = localPort;

 Thread server = new Thread(new Runnable() {

   @Override
   public void run() {
     try {
       peerSock = new ServerSocket();
       System.out.println(peerSock.isBound());
       peerSock.setReuseAddress(true);
       System.out.println(peerSock.isBound());
       peerSock.bind(new InetSocketAddress("localhost", localport));
       System.out.println("[Server]The server is listening on " + localport + ".");
       System.out.println(peerSock.isBound());
       System.out.println(peerSock.isClosed());
       System.out.println(peerSock.getLocalSocketAddress().toString());
       //peerSock.
       while (true) {
         try {
           serverSocket = peerSock.accept();
           // just means finishing handshaking, and connection
           // established.
           System.out.println("[Server]New connection accepted"
                   + serverSocket.getInetAddress() + ":" + serverSocket.getPort());

           BufferedReader br = getReader(serverSocket);
           PrintWriter pw = getWriter(serverSocket);
           String req = br.readLine();
           System.out.println("[Server][REQ]" + req);
           pw.println(req);

 //              pw.close();
 //              br.close();
         } catch (IOException e) {
           e.printStackTrace();
         } finally {
 //              try {
 //                if (serverSocket != null)
 //                  serverSocket.close();
 //              } catch (IOException e) {
 //                e.printStackTrace();
 //              }
         }
       }
     } catch (Exception e) {
       e.printStackTrace();
     }
   }

 });
 // server.setDaemon(true);
 server.start();

 Thread.currentThread();
 // sleep several seconds before launch of client
 Thread.sleep(5 * 1000);

 final int retry = 5;
 Thread client = new Thread(new Runnable() {

   @Override
   public void run() {
     Socket socket = new Socket();
     try {
       socket.setReuseAddress(true);
       System.out.println("[Client]socket.isBound():" + socket.isBound());
       socket.bind(new InetSocketAddress("localhost", localport));
       for (int i = 1; i < retry; i++) {
         try {
           socket.connect(new InetSocketAddress(serverHost, serverPort));
           System.out.println("[Client]connect to " + serverHost + ":"
                   + serverPort + " successfully.");
           break;
         } catch (Exception e) {
           System.out.println("[Client]fail to connect " + serverHost + ":"
                   + serverPort + ", try again.");
           Thread.currentThread().sleep(i * 2 * 1000);
           /**
            * PeerA and PeerB
            * <p>
            * Alternatively, A's TCP implementation might
            * instead notice that A has an active listen socket
            * on that port waiting for incoming connection
            * attempts. Since B's SYN looks like an incoming
            * connection attempt, A's TCP creates a new stream
            * socket with which to associate the new TCP
            * session, and hands this new socket to the
            * application via the application's next accept()
            * call on its listen socket. A's TCP then responds
            * to B with a SYN-ACK as above, and TCP connection
            * setup proceeds as usual for client/server-style
            * connections.
            * <p>
            * Since A's prior outbound connect() attempt to B
            * used a combination of source and destination
            * endpoints that is now in use by another socket,
            * namely the one just returned to the application
            * via accept(), A's asynchronous connect() attempt
            * must fail at some point, typically with an
            * “address in use” error. The application
            * nevertheless has the working peer-to- peer stream
            * socket it needs to communicate with B, so it
            * ignores this failure.
            */
           if (i == retry - 1) {
             System.out
                     .println("[Client]Use the socket returned by ServerSocket.");

             socket = serverSocket;
           }
         }
       }

       PrintWriter pw = getWriter(socket);
       String msg = "hello world!";
       pw.println(msg);

       /**
        * Got response from the server socket.
        */
       BufferedReader br = getReader(socket);
       String resp = br.readLine();
       System.out.println("[Client][RESP-1]" + resp);

       /**
        * The client thread of other process will send request. If
        * fail to establish connection with other peer, the Socket
        * return by the ServerSocket will be used.
        */
       resp = br.readLine();
       System.out.println("[Client][RESP-2]" + resp);
//          pw.close();
//          br.close();
     } catch (Exception e) {
       e.printStackTrace();
     } finally {
//          try {
//            socket.close();
//          } catch (Exception e) {
//            e.printStackTrace();
//          }
     }
   }

 });
 client.start();
  }

  private PrintWriter getWriter(Socket socket) throws IOException {
    OutputStream socketOut = socket.getOutputStream();
    return new PrintWriter(socketOut, true);
  }

  private BufferedReader getReader(Socket socket) throws IOException {
    InputStream socketIn = socket.getInputStream();
    return new BufferedReader(new InputStreamReader(socketIn));
  }

  public static void main(String[] args) throws Exception {
   new TcpPeer2("127.0.0.1", 8000, 7000);
  }
}
导入java.io.BufferedReader;
导入java.io.IOException;
导入java.io.InputStream;
导入java.io.InputStreamReader;
导入java.io.OutputStream;
导入java.io.PrintWriter;
导入java.net.InetSocketAddress;
导入java.net.ServerSocket;
导入java.net.Socket;
/**
*仅用于测试插座,所以请重新阅读。如果将SO_reseaddr设置为true,我们可以使用
*一个本地端口,用于侦听传入的TCP连接并启动
*同时有多个传出TCP连接。这样我们就可以实施
*TCP打孔(通过TCP上的NAT建立P2P连接遍历)。
*/
公共类Tcpeer2{
//TCP端口与UDP端口是不同的源,这意味着您可以侦听
//TCP和UDP同时使用同一端口。
专用int localport=7890;
专用服务器套接字peerSock;
专用套接字服务器套接字;
公共TcpPeer2(最终字符串serverHost、最终int serverPort、最终int localPort)
抛出异常{
this.localport=localport;
线程服务器=新线程(newrunnable(){
@凌驾
公开募捐{
试一试{
peerSock=newserversocket();
System.out.println(peerSock.isBound());
peerSock.setReuseAddress(真);
System.out.println(peerSock.isBound());
bind(新的InetSocketAddress(“localhost”,localport));
System.out.println(“[Server]服务器正在侦听”+localport+”);
System.out.println(peerSock.isBound());
System.out.println(peerSock.isClosed());
System.out.println(peerSock.getLocalSocketAddress().toString());
//皮尔斯托克。
while(true){
试一试{
serverSocket=peerSock.accept();
//就意味着完成握手和连接
//建立。
System.out.println(“[Server]已接受新连接”
+serverSocket.getInetAddress()+“:”+serverSocket.getPort());
BufferedReader br=getReader(服务器套接字);
PrintWriter pw=getWriter(服务器套接字);
String req=br.readLine();
System.out.println(“[Server][REQ]”+REQ);
pw.println(要求);
//关闭();
//br.close();
}捕获(IOE异常){
e、 printStackTrace();
}最后{
//试一试{
//if(serverSocket!=null)
//serverSocket.close();
//}捕获(IOE异常){
//e.printStackTrace();
//              }
}
}
}捕获(例外e){
e、 printStackTrace();
}
}
});
//setDaemon(true);
server.start();
Thread.currentThread();
//在启动客户端之前睡眠几秒钟
线程。睡眠(5*1000);
最终整数重试=5;
线程客户端=新线程(新可运行(){
@凌驾
公开募捐{
套接字=新套接字();
试一试{
socket.setReuseAddress(真);
System.out.println(“[Client]socket.isBound():”+socket.isBound());
bind(新的InetSocketAddress(“localhost”,localport));
for(int i=1;i