两台不同局域网的主机可以不通过公网服务器进行通讯吗?

如果我事先知道两台不同局域网的主机的映射IP地址和映射端口号,并且双方都通过某种网络通讯工具(socket)向对方发送数据,使双方的路由器建立映射表,那么可以不通过公网服务器进行通讯吗?

  • 你可以看下这个问题的回答https://ask.csdn.net/questions/7769353
  • 除此之外, 这篇博客: 网络编程中的 (1). 创建 Socket:根据指定服务端的 IP 地址或端口号构造Socket类对象。若服务器端响应,则建立客户端到服务器的通信线路。若连接失败,会出现异常。 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
  • // 向服务器(域名是host。端口号为port)发起TCP连接,若成功,则创建Socket对象,否则抛出异常。
    Scocket socket = new Socket(InetAddress.getByName("LAPTOP-RSJSE505"),9999);
    // 根据InetAddress对象所表示的IP地址以及端口号port发起连接。
    Socket socket = new Socket(InetAddress.getByName("172.17.31.57"),9999);
    
  • 以下回答由chatgpt基于相关博客总结生成:

    对于两台不同局域网的主机,在没有公网服务器的情况下进行通讯并不是一件容易的事情。因为局域网和公网是隔离的,也就是说,两台主机之间是无法直接通讯的。但是,在一些特殊情况下,可以通过使用NAT(网络地址转换)来实现两台主机之间的通讯。

    具体实现方法如下:

    1. 在两台主机上都安装一个支持UPnP协议的软件,如端口映射工具。

    2. 在局域网中,通过UPnP协议向路由器申请外网IP和端口的映射。

    3. 通过UPnP协议向路由器注册一个回调监听函数,以便在路由器映射规则发生变化时能够及时得到通知。

    4. 在程序中设置一个监听端口并绑定到本地IP地址。

    5. 创建一个套接字并连接远程主机的映射IP地址和端口号。

    6. 发送数据。

    7. 接收数据。

    参考代码如下:

    import java.net.*;
    import java.io.*;
    
    public class Client {
    
       public static void main(String [] args) {
          String serverName = "192.168.1.100";
          int port = 9999;
          try {
             // 创建一个套接字并连接远程主机的映射IP地址和端口号
             Socket client = new Socket(serverName, port);
             System.out.println("已连接到主机: " + client.getRemoteSocketAddress());
             // 发送数据
             OutputStream outToServer = client.getOutputStream();
             DataOutputStream out = new DataOutputStream(outToServer);
             out.writeUTF("Hello from " + client.getLocalSocketAddress());
             // 接收数据
             InputStream inFromServer = client.getInputStream();
             DataInputStream in = new DataInputStream(inFromServer);
             System.out.println("服务器响应: " + in.readUTF());
             // 关闭套接字
             client.close();
          } catch (IOException e) {
             e.printStackTrace();
          }
       }
    }
    
    import java.net.*;
    import java.io.*;
    
    public class Server extends Thread {
       private ServerSocket serverSocket;
    
       public Server(int port) throws IOException {
          // 在程序中设置一个监听端口并绑定到本地IP地址
          serverSocket = new ServerSocket(port);
          serverSocket.setSoTimeout(100000);
       }
    
       public void run() {
          while(true) {
             try {
                System.out.println("等待远程连接,端口号为:" + serverSocket.getLocalPort() + "...");
                // 等待客户端连接
                Socket server = serverSocket.accept();
                System.out.println("远程主机地址:" + server.getRemoteSocketAddress());
                // 接收数据
                DataInputStream in = new DataInputStream(server.getInputStream());
                System.out.println(in.readUTF());
                // 向客户端发送响应数据
                DataOutputStream out = new DataOutputStream(server.getOutputStream());
                out.writeUTF("谢谢连接我:" + server.getLocalSocketAddress() + "\nGoodbye!");
                // 关闭套接字
                server.close();
             } catch (SocketTimeoutException s) {
                System.out.println("Socket timed out!");
                break;
             } catch (IOException e) {
                e.printStackTrace();
                break;
             }
          }
       }
    
       public static void main(String [] args) {
          int port = 9999;
          try {
             // 开启服务器监听
             Thread t = new Server(port);
             t.start();
          } catch (IOException e) {
             e.printStackTrace();
          }
       }
    }
    

    需要特别注意,因为NAT的运作机制是根据TCP/UDP数据包的头字段进行操作,所以使用非标准的TCP/UDP数据包(例如自定义TCP/UDP数据包)可能会导致NAT无法工作。此外,由于UPnP协议实现较为复杂,在使用过程中也要注意网络安全问题。

用什么工具通讯不重要,之所以外网不能连接内网就是因为路由器没有映射关系,现在知道访问成功路由器会建立映射关系,如果访问失败路由器会不会建立映射关系?