Python跨路由器TCP套接字连接失败,报WinError 10060错误
问题
同一网络下用Python搭建的TCP套接字运行正常,但跨网络时无法连接。已将服务器绑定IP设为0.0.0.0,但客户端连接时出现socket错误10060。推测问题出在端口转发,但不知道如何配置。同时不清楚如何用Python获取设备公网IP(gethostbyname()仅返回私网IP),寻求帮助。
测试代码
Server.py
import socket import struct def send_msg(sock, msg): msg = struct.pack('>Q', len(msg)) + msg sock.sendall(msg) def recv_msg(sock): raw_msglen = recvall(sock, 8) if not raw_msglen: return None msglen = struct.unpack('>Q', raw_msglen)[0] return recvall(sock, msglen) def recvall(sock: socket.socket, n): data = bytearray() while len(data) < n: packet = sock.recv(n - len(data)) if not packet: return None data.extend(packet) return data HOST = '0.0.0.0' PORT = 5000 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind((HOST, PORT)) s.listen() conn, addr = s.accept() with conn: while True: text = input("Enter text: ").encode("utf-8") send_msg(conn,text) echo = recv_msg(conn).decode("utf-8") print(echo)
(注:原代码缺少import socket和import struct,已补充)
Client.py
import socket import struct def send_msg(sock, msg): msg = struct.pack('>Q', len(msg)) + msg sock.sendall(msg) def recv_msg(sock): raw_msglen = recvall(sock, 8) if not raw_msglen: return None msglen = struct.unpack('>Q', raw_msglen)[0] return recvall(sock, msglen) def recvall(sock: socket.socket, n): data = bytearray() while len(data) < n: packet = sock.recv(n - len(data)) if not packet: return None data.extend(packet) return data #HOST = '192.168.0.220' HOST = 'x.x.x.x' # 服务器公网IP PORT = 5000 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((HOST, PORT)) while True: data = recv_msg(s) send_msg(s,data)
解决方案
1. 配置端口转发
跨网络访问需在服务器所在路由器上配置端口转发,步骤如下:
- 登录路由器管理后台(通常在浏览器输入
192.168.1.1或192.168.0.1,具体参考路由器说明书) - 找到端口转发或虚拟服务器选项
- 添加转发规则:
- 外部端口:填写服务器监听的端口(如5000)
- 内部端口:与外部端口保持一致(5000)
- 内部IP地址:服务器设备的内网IP(可通过
ipconfig(Windows)或ifconfig(Linux/macOS)查看) - 协议:选择
TCP
- 保存规则后重启路由器生效
2. 获取公网IP的Python方法
gethostbyname()仅能获取内网IP,要获取公网IP需访问外部服务,示例代码如下:
import requests def get_public_ip(): try: response = requests.get('http://httpbin.org/ip') return response.json()['origin'] except Exception as e: print(f"获取公网IP失败: {e}") return None if __name__ == "__main__": public_ip = get_public_ip() if public_ip: print(f"公网IP: {public_ip}")
(注:需先安装requests库,执行pip install requests)
3. 额外注意事项
- 确保服务器设备防火墙开放监听端口(5000):Windows可在防火墙高级设置中添加入站规则;Linux执行
ufw allow 5000/tcp - 部分运营商会使用CGNAT(运营商级NAT),此时设备无独立公网IP,端口转发无效,需使用内网穿透工具(如frp、ngrok)
- 客户端连接时,
HOST必须填写服务器的公网IP,而非内网IP
内容的提问来源于stack exchange,提问作者Beasty
相关产品推荐
相关产品推荐

