来自本地网络的 WebSocket 连接在连接到本地网络服务器时都使用相同的客户端端口(而不是临时端口)——为什么?

来自本地网络的 WebSocket 连接在连接到本地网络服务器时都使用相同的客户端端口(而不是临时端口)——为什么?

我在家用台式机上的虚拟机上设置了一个 Web 服务器。我让路由器将多个端口(80、443 等)转发到我的台式机,然后通过 NAT 将它们转发到虚拟机(请参阅图表举例来说)。在运行简单的 Apache 服务器时,这似乎工作得很好。然而,当我尝试使用 WebSockets 时,我遇到了问题。

我设置了一个简单的 WebSocket 回显服务器(完全复制自https://www.boost.org/doc/libs/master/libs/beast/example/websocket/server/async-ssl/websocket_server_async_ssl.cpp除了当然要将 SSL 证书更改为我自己的证书之外)监听端口 6164,然后以与其他人相同的方式转发。我还在前面提到的 apache 服务器上建立了一个简单的网页(下面的代码供参考),以打开到服务器的 websocket 并发送消息。

服务器似乎完全按照预期工作,我可以打开 WebSocket 连接,并发送一条回显的消息等。但是,我注意到,每次我从本地网络上的计算机(或其他设备)打开 WebSocket 时,它总是两端均使用端口 6164,因此一次只能从我的本地网络发起一个连接。对于来自本地网络之外的设备的连接,情况并非如此,它们在客户端使用临时端口。(请参阅端口分解图用于测试用例)。

  1. 为什么会发生这种情况?
  2. 是否有工具可以帮助我追踪整个连接路径上发生的情况?(例如,它通过哪些 IP/端口转发)
  3. 由于我对网络还不太熟悉:到底是什么决定了客户端的端口?是浏览器自己选择一个端口吗?

一些额外的信息:当我检查 netstat 时,监听器显示

tcp 0 0 0.0.0.0:6164 0.0.0.0:* 侦听 26866/./服务...

当我网络上的任何计算机(或我的手机)连接时,它会显示

tcp 0 0 10.0.2.15:6164 10.0.2.2:6164 已建立 26866/./服务...

但当我断开手机与网络的连接并使用数据,或使用不在本地网络上的计算机时,它会显示

tcp 0 0 10.0.2.15:6164 10.0.2.2:51616 已建立 26866/./服务...

其中 51616 临时端口号每次都会变化。10.0.2.15 是我的虚拟机的 IP,10.0.2.2 是虚拟机的网关。

此外,这并非端口 6164 所特有的,我尝试让服务器监听其他几个端口,并ws = new WebSocket("wss://shaun.ralsum.com:6164");相应地更改代码中的行,结果相同。

编辑:这里这是根据用户 1686 的要求,我的路由器->桌面(左)和桌面->VM(右)的端口转发规则的图像。


网页代码

<!DOCTYPE HTML>

<html>
  <head>
    
    <script>
      function openConnection(){
      if(window.WebSocket){
          // Open a web socket
          ws = new WebSocket("wss://shaun.ralsum.com:6164");
          ws.onopen = function(){
          ws.send("socket open");
          document.getElementById('socketStatus').innerHTML =
              "socket connected";
          };
          ws.onmessage = function(evt){
          var recievedMessage = evt.data;
          document.getElementById('serverResponse').innerHTML =
              recievedMessage;
          };
      } else{
          document.getElementById('socketStatus').innerHTML =
          "WebSockets not supported";
      }
      }

      function sendMessage(){
      // use global web socket object to send a message
      ws.send("sending another message");
      }
      
      function closeConnection(){
      // close the web socket connection
      ws.close();
      document.getElementById('socketStatus').innerHTML =
          "socket disconnected";
      }
    </script>
    
  </head>
  
  <body>
    <p id="socketStatus">socket disconnected</p>
    <button onclick="openConnection()">create socket</button>
    <button onclick="sendMessage()">send message</button>
    <button onclick="closeConnection()">close socket</button>
    <p id="serverResponse">response from server</p>
  </body>
  
</html>

注意:最初发布到 stack overflow,但被建议改为发布到这里。

相关内容