Python单服务器消息平台跨公网连接拒绝/超时问题求助
问题描述
我正在用Python开发单服务器架构的消息平台,目前已完成防火墙、端口转发及路由配置。该服务器-客户端架构在同一机器上可正常运行,但我希望通过公网IP实现两台设备跨互联网通信。尝试使用Keenetic路由器的WiFi公网IP(178.140.168.19)连接时,频繁出现“connection refused”或“connection timed out”错误,客户端信号似乎未到达服务器。
平台支持Linux和Windows系统(推荐用Linux,忽略代码中的cls,属于遗留代码),所有功能在Python 3.7环境下均可正常工作。
服务器代码
import threading import socket import time import os as r r.system(" ") clients = set() clients_lock = threading.Lock() def announce(msg): with clients_lock: for c in clients: c.sendall(msg.encode("utf-8")) print(msg) def handle_client(conn, addr): client = conn with clients_lock: clients.add(conn) while True: try: try: data = conn.recv(1024) d = data.decode() d = d.split("\x00\x12\x12") # data splitting (text - nick) except BaseException as b: print(f"\033[1;37;41m<System> {addr[0]}:{addr[1]} {b} ") print(f"\033[1;37;41m<System> {addr[0]}:{addr[1]}, DONT EVER RETURN HERE AGAIN\033[0m") conn.close() clients.remove(client) break if not data: pass if d[0]=="/closecon": announce(f"\033[1;37;42m<System> {addr[0]}:{addr[1]}, bye") conn.close() clients.remove(client) break try: announce(f"\033[1;37;40m< {addr[0]}:{addr[1]} / \033[1;33;40m{d[1]}\033[1;37;40m > {d[0]} \033[0m") except BaseException as v: conn.close() clients.remove(client) announce(f"\033[1;37;42m<System> {addr[0]}:{addr[1]}, bye ({v})") except KeyboardInterrupt: print("bye!") s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ip = "" # local ip s.bind((ip, 10000)) # 8000 - 12000, the ports that mine machine accepts s.listen(30) print("Server started") while True: conn, addr = s.accept() announce("\033[1;32;40maccepting new client, username unknown\033[0m") print("\033[1;32;40maccepting new client, username unknown\033[0m") thread = threading.Thread(target=handle_client, args=(conn, addr)) thread.start()
客户端代码
import socket import threading import os as r;r.system("") s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('192.168.1.33', 10000)) loginName = input("Hello user, what's your name?\n > ") r.system("cls") def print_others_msg(): global ypos while True: data = s.recv(1024) if data: print(f"> {data.decode()}"+" "*70) thread = threading.Thread(target=print_others_msg) ;thread.start() while True: toSend = str(input("")+"\x00\x12\x12"+loginName).strip(" ") if len(toSend)>70: print("Text size limit!! >70 ") else: s.send(toSend.encode('utf8'))
排查解决方案
验证端口转发有效性:
- 确认路由器端口转发规则是将公网端口10000映射到服务器局域网IP(如
192.168.1.33)及10000端口,协议选择TCP。 - 用外部网络设备测试公网端口是否开放:
若连接失败,说明端口转发未配置正确或被拦截。# Linux/macOS nc -zv 178.140.168.19 10000 # Windows telnet 178.140.168.19 10000
- 确认路由器端口转发规则是将公网端口10000映射到服务器局域网IP(如
检查服务器防火墙:
确保服务器防火墙允许10000端口的TCP入站连接:# Linux ufw命令 sudo ufw allow 10000/tcp sudo ufw reloadWindows需在 Defender防火墙中添加对应端口的入站规则。
确认服务器网络配置:
服务器代码中ip = ""绑定所有网卡是正确的,但要确保服务器局域网IP为静态分配(避免重启后IP变化导致端口转发失效),且该IP与端口转发规则中的目标IP一致。排查运营商NAT限制:
部分家庭宽带的公网IP是运营商NAT后的“假公网”,此时外部无法直接访问。可通过手机流量网络测试连接,若仍失败,需联系运营商获取真实公网IP。修改客户端连接地址:
客户端连接公网时,需将s.connect(('192.168.1.33', 10000))修改为s.connect(('178.140.168.19', 10000)),且不要在局域网内测试公网IP连接(部分路由器不支持NAT回环)。
内容的提问来源于stack exchange,提问作者UA3YSR
相关产品推荐
相关产品推荐

