私は自宅のデスクトップ上の仮想マシンにウェブサーバーを設置しました。ルーターでいくつかのポート(80、443など)をデスクトップに転送し、NAT経由で仮想マシンに転送します(図(説明のため)。これは、単純な Apache サーバーを実行する場合は問題なく動作するようです。ただし、WebSocket を使用しようとすると問題が発生します。
シンプルなWebSocketエコーサーバーをセットアップしました(https://www.boost.org/doc/libs/master/libs/beast/example/websocket/server/async-ssl/websocket_server_async_ssl.cppもちろん、SSL 証明書を自分のものに変更することを除いて)、ポート 6164 でリッスンし、他のものと同じ方法で転送します。また、前に述べた Apache サーバーでホストされている簡単な Web ページ (以下のコードは参考用) を設定し、サーバーへの Websocket を開いてメッセージを送信します。
サーバーは意図したとおりに動作しているようで、WebSocket接続を開いてメッセージを送信し、エコーバックされるなどできます。しかし、ローカルネットワーク上のコンピューター(または他のデバイス)からWebSocketを開くたびに、いつも両側でポート6164を使用するため、ローカルネットワークからの接続は一度に1つしか発生しません。ローカルネットワーク外のデバイスからの接続の場合は、クライアント側で一時ポートが使用されます。(ポートの内訳図(テスト済みのケースの場合)
- なぜこうなった?
- 接続のパス全体にわたって何が起こっているかを追跡するために使用できるツールはありますか? (つまり、どの IP/ポートを経由して転送されているか)
- 私はネットワークに関しては初心者なのですが、クライアントのポートは何によって決まるのでしょうか? ブラウザ自体がポートを選択するだけなのでしょうか?
少し追加情報:netstatをチェックすると、リスナーは次のように表示します
tcp 0 0 0.0.0.0:6164 0.0.0.0:* LISTEN 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 のゲートウェイです。
ws = new WebSocket("wss://shaun.ralsum.com:6164");
さらに、これはポート 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>
注: 元々は Stack Overflow に投稿されましたが、代わりにここに投稿するようにアドバイスされました。