로컬 네트워크에서 시작되는 WebSocket 연결은 모두 로컬 웹 서버에 연결할 때 임시 포트 대신 동일한 클라이언트 측 포트를 사용합니다. 이유는 무엇입니까?

로컬 네트워크에서 시작되는 WebSocket 연결은 모두 로컬 웹 서버에 연결할 때 임시 포트 대신 동일한 클라이언트 측 포트를 사용합니다. 이유는 무엇입니까?

내 집 데스크탑의 가상 머신에 웹 서버를 설정했습니다. 라우터에서 여러 포트(80, 443 등)를 데스크탑으로 전달한 후 NAT를 통해 가상 머신으로 전달합니다(참조:도표예시용). 이것은 간단한 아파치 서버를 실행할 때 잘 작동하는 것 같습니다. 그러나 WebSocket을 사용하려고 할 때 문제가 발생합니다.

간단한 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을 열 때마다 네트워크, 그것언제나양쪽에서 포트 6164를 사용하므로 로컬 네트워크에서 한 번에 하나의 연결만 발생할 수 있습니다. 내 로컬 네트워크 외부의 장치에서 시작되는 연결의 경우에는 해당되지 않으며 클라이언트 측의 임시 포트를 사용합니다. (보다포트 분석 다이어그램테스트된 경우).

  1. 왜 이런 일이 발생합니까?
  2. 전체 경로를 따라 연결에 어떤 일이 일어나고 있는지 추적하는 데 사용할 수 있는 도구가 있습니까? (즉, 어떤 IP/포트를 통해 전달됩니까?)
  3. 나는 네트워킹에 익숙하지 않기 때문에 어쨌든 클라이언트 포트를 결정하는 것은 무엇입니까? 브라우저 자체가 하나를 선택하는 것일까요?

약간의 추가 정보: netstat를 확인하면 리스너에 다음이 표시됩니다.

tcp 0 0 0.0.0.0:6164 0.0.0.0:* 듣기 26866/./serv...

내 네트워크에 있는 컴퓨터(또는 내 휴대폰)가 연결되면 다음이 표시됩니다.

tcp 0 0 10.0.2.15:6164 10.0.2.2:6164 설정됨 26866/./serv...

하지만 네트워크에서 휴대폰 연결을 끊고 데이터를 사용하거나 로컬 네트워크에 없는 컴퓨터를 사용하면 다음과 같은 내용이 표시됩니다.

tcp 0 0 10.0.2.15:6164 10.0.2.2:51616 설정됨 26866/./serv...

여기서 51616 임시 포트 번호는 매번 변경됩니다. 10.0.2.15는 내 VM의 IP이고 10.0.2.2는 VM의 게이트웨이입니다.

또한 이는 포트 6164에만 해당되는 것이 아니기 때문에 서버가 다른 여러 포트에서 수신 대기하도록 하여 ws = new WebSocket("wss://shaun.ralsum.com:6164");이에 따라 코드 줄을 변경해 보았지만 결과는 동일했습니다.

편집하다:여기다음은 user1686이 요청한 라우터->데스크톱(왼쪽) 및 데스크톱->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>

참고: 원래는 스택 오버플로에 게시되었지만 대신 여기에 게시하는 것이 좋습니다.

관련 정보