同一机器多WebSocket客户端连接服务器端口冲突问题求助
问题描述
我在家庭服务器部署了Python WebSocket服务,单客户端连接正常,但同一客户端机器启动多个实例时,必须等第一个客户端断开后,后续实例才能建立连接;不同机器或服务器本地运行多客户端则可正常同时连接。经netstat排查,客户端本地端口各不相同,但外发的远程端口均固定为服务器WebSocket端口3000,导致连接冲突。因无法修改客户端代码,需从系统或服务器端解决该问题。设备环境:客户端为Fedora 39(KDE Plasma),服务器为RHEL系操作系统。
服务器代码如下:
import asyncio import websockets # identifies the port PORT = "3000" # identifies the hostname HOST = "rx-78-2" # sets the trust message that essentially acts as a secondary handshake TURTLE_MESSAGE = "Shake my hand bro" # sets the message that will indicate a disconnection DISCONNECT_MESSAGE = "END-OF-LINE" turtles = [] # handles a new connection async def handle_connect(websocket, path): print(f"CONNECTION RECIEVED @ {path}") turtleIndex = len(turtles) turtles.append(f"Turtle {len(turtles)}") print(turtles[turtleIndex]) connected = True first_msg = await websocket.recv() if first_msg != TURTLE_MESSAGE: print("Connection Refused") await websocket.send("return print('Connection Refused')") await websocket.close() else: print("Connection Established") await websocket.send("return print('Connection Established')") while connected: msg = await websocket.recv() if msg == DISCONNECT_MESSAGE: break print(msg) await websocket.send("return turtle.turnRight()") print("CLOSING SOCKET") async def main(): async with websockets.serve(handle_connect, HOST, PORT, ssl=None, compression=None): await asyncio.Future() print("STARTING SERVER") asyncio.run(main())
解决方案
1. 调整服务器绑定IP
当前代码中HOST = "rx-78-2"仅绑定到服务器主机名对应的特定IP,可能导致同一客户端多实例连接时出现异常。修改为监听所有网卡:
HOST = "0.0.0.0"
重启WebSocket服务后测试连接。
2. 优化服务器系统参数
提升文件描述符限制
WebSocket连接依赖系统文件描述符,默认限制可能过低,无法支撑多并发连接:
- 临时生效:执行
ulimit -n 65535(仅当前会话有效) - 永久生效:编辑
/etc/security/limits.conf,添加以下内容:
重启服务器后生效。* soft nofile 65535 * hard nofile 65535
增大TCP半连接队列
调整tcp_max_syn_backlog参数,避免客户端SYN请求被丢弃:
- 临时生效:
sysctl -w net.ipv4.tcp_max_syn_backlog=4096 - 永久生效:编辑
/etc/sysctl.conf,添加net.ipv4.tcp_max_syn_backlog = 4096,执行sysctl -p使配置生效。
3. 优化客户端机器(Fedora 39)TCP参数
开启TIME_WAIT端口复用
允许处于TIME_WAIT状态的端口被快速复用,缓解同一客户端多实例的连接冲突:
- 临时生效:
sysctl -w net.ipv4.tcp_tw_reuse=1 sysctl -w net.ipv4.tcp_fin_timeout=30 - 永久生效:编辑
/etc/sysctl.conf,添加:
执行net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_fin_timeout = 30sysctl -p使配置生效。
扩大本地端口范围
增加客户端可用的本地端口数量,避免端口耗尽:
- 临时生效:
sysctl -w net.ipv4.ip_local_port_range="1024 65535" - 永久生效:编辑
/etc/sysctl.conf,添加net.ipv4.ip_local_port_range = 1024 65535,执行sysctl -p使配置生效。
4. 服务器端部署负载均衡(可选)
若上述方法无效,可通过Nginx实现负载均衡,将客户端请求分发到多个WebSocket服务实例:
- 启动多个WebSocket服务实例,分别绑定3001、3002等不同端口
- 配置Nginx:
http { upstream websocket_backend { server 127.0.0.1:3001; server 127.0.0.1:3002; } server { listen 3000; location / { proxy_pass http://websocket_backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; } } } - 重启Nginx服务,客户端仍连接3000端口即可实现并发连接。
内容的提问来源于stack exchange,提问作者BlackDiamond
相关产品推荐
相关产品推荐

