我在家用台式机上的虚拟机上设置了一个 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,因此一次只能从我的本地网络发起一个连接。对于来自本地网络之外的设备的连接,情况并非如此,它们在客户端使用临时端口。(请参阅端口分解图用于测试用例)。
- 为什么会发生这种情况?
- 是否有工具可以帮助我追踪整个连接路径上发生的情况?(例如,它通过哪些 IP/端口转发)
- 由于我对网络还不太熟悉:到底是什么决定了客户端的端口?是浏览器自己选择一个端口吗?
一些额外的信息:当我检查 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,但被建议改为发布到这里。