EC2 Linux实例无法建立WebSocket连接,请求部署安全WebSocket聊天服务协助
一、解决“远程系统拒绝连接”问题
1. 修正服务器监听地址
你的WebSocket服务器代码当前绑定的是localhost,这意味着仅能在EC2实例内部访问,外部客户端无法连接。将监听地址改为0.0.0.0,让服务器监听实例的所有网卡:
import websockets import asyncio PORT = 8080 print(f'Server is listening on port: {PORT}') connected = set() async def echo(ws_client, path): print('A Client just connected!') connected.add(ws_client) try: async for message in ws_client: print('Received message from client:' + message) for conn in connected: if conn != ws_client: await conn.send(message) except websockets.exceptions.ConnectionClosed as e: print('A Client just disconnected!') finally: connected.remove(ws_client) # 关键修改:将localhost改为0.0.0.0 server = websockets.serve(echo, '0.0.0.0', PORT) asyncio.get_event_loop().run_until_complete(server) asyncio.get_event_loop().run_forever()
2. 确认安全组配置
确保EC2安全组的入站规则包含以下设置:
- 规则类型:自定义TCP
- 端口范围:8080
- 源地址:测试阶段可设为
0.0.0.0/0(允许所有IP访问),生产环境建议限制为特定IP段 - 描述:WebSocket Server
3. 检查实例网络与本地防火墙
- 客户端连接时必须使用EC2的公有IP/弹性IP,而非私有IP
- 若EC2实例启用了本地防火墙(如ufw、iptables),需开放8080端口:
# 针对ufw sudo ufw allow 8080/tcp # 针对iptables sudo iptables -A INPUT -p tcp --dport 8080 -j ACCEPT
4. 测试基础连通性
修改代码后重启服务器,在本地用telnet验证网络是否通:
telnet <EC2公有IP> 8080
若能建立连接,再运行客户端代码测试WebSocket通信。
二、部署安全WebSocket(WSS)服务
要实现加密的WebSocket连接,需配置SSL证书,推荐使用Let's Encrypt免费证书。
1. 在EC2上获取SSL证书
# 更新系统包并安装Certbot sudo apt update && sudo apt install certbot -y # 获取证书(替换为你的域名,需先将域名解析到EC2公有IP) sudo certbot certonly --standalone -d your-domain.com
证书会生成在/etc/letsencrypt/live/your-domain.com/目录,包含fullchain.pem(证书链)和privkey.pem(私钥)。
2. 修改服务器代码支持WSS
import websockets import asyncio import ssl PORT = 443 # WSS默认使用443端口,也可自定义为8443 print(f'Secure Server is listening on port: {PORT}') connected = set() # 加载SSL证书 ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) ssl_context.load_cert_chain( certfile='/etc/letsencrypt/live/your-domain.com/fullchain.pem', keyfile='/etc/letsencrypt/live/your-domain.com/privkey.pem' ) async def echo(ws_client, path): print('A Client just connected!') connected.add(ws_client) try: async for message in ws_client: print('Received message from client:' + message) for conn in connected: if conn != ws_client: await conn.send(message) except websockets.exceptions.ConnectionClosed as e: print('A Client just disconnected!') finally: connected.remove(ws_client) # 启动加密WebSocket服务器 server = websockets.serve(echo, '0.0.0.0', PORT, ssl=ssl_context) asyncio.get_event_loop().run_until_complete(server) asyncio.get_event_loop().run_forever()
3. 更新安全组与防火墙
- 安全组入站规则添加TCP 443端口(或自定义的8443端口)
- 本地防火墙开放对应端口:
sudo ufw allow 443/tcp
4. 修改客户端代码连接WSS
同时修复原客户端代码中input()阻塞事件循环的问题:
import websockets import asyncio async def get_input(): return input() async def listen(): # 替换为你的域名,使用wss协议 url = 'wss://your-domain.com' async with websockets.connect(url) as ws: await ws.send('Hello secure server!') while True: # 同时处理用户输入和消息接收,避免阻塞 input_task = asyncio.create_task(get_input()) recv_task = asyncio.create_task(ws.recv()) done, pending = await asyncio.wait( [input_task, recv_task], return_when=asyncio.FIRST_COMPLETED ) if input_task in done: msg = input_task.result() await ws.send(msg) if recv_task in done: msg = recv_task.result() print(msg) # 取消未完成的任务 for task in pending: task.cancel() asyncio.get_event_loop().run_until_complete(listen())
三、额外优化建议
- 使用systemd创建服务配置,确保WebSocket服务器随EC2实例开机自动启动
- 生产环境可搭配Nginx反向代理WSS服务,提升并发能力与稳定性
- 增加消息处理的异常捕获逻辑,避免单个客户端异常导致服务器崩溃
内容的提问来源于stack exchange,提问作者Aaditya Prabu K
相关产品推荐
相关产品推荐

