Python Socket跨两台机器无法连接及WinError 10038错误排查求助
问题排查与解决方案
我来帮你拆解这两个常见的Socket开发问题,咱们逐个解决:
一、WinError 10038 错误的根源与修复
这个错误的本质是你在已经关闭的套接字对象上执行了操作。看你的客户端代码就能发现问题:
客户端的run函数里写了一个无限循环,一直调用_socket.recv()接收服务器命令,但当客户端执行完服务器发送的_socket.close()后,_socket已经被关闭,可循环还在继续跑,下一次再调用recv()时,就会触发「尝试对非套接字操作」的错误(WinError 10038)。
具体修复步骤:
- 客户端修改:让客户端在执行关闭命令后跳出循环,避免无效操作。比如给关闭命令加个判断,执行后终止循环:
import socket def run(mode='client'): _socket = socket.socket() _socket.connect(('192.168.0.101', 1234)) keep_running = True while keep_running: command = _socket.recv(1024).decode('utf-8') # 检测到关闭命令时,执行后终止循环 if command == "_socket.close()": exec(command) keep_running = False else: exec(command) while True: try: run() # 正常退出后稍作休息再重连,避免频繁重试 import time time.sleep(1) except OSError as e: print(f"连接出错啦: {e}") import time time.sleep(1)
- 服务器端补充:处理完每个客户端请求后,主动关闭客户端套接字
c,避免资源泄漏(虽然不是直接导致10038的原因,但能让服务器更稳定):
在服务器代码的这两个位置添加c.close():
# 处理无效主机名的分支 except: c.send(bytes('''print("The hostname is either invalid or wasn't found")''','utf-8')) c.send(bytes('_socket.close()','utf-8')) c.close() # 新增:关闭客户端连接 continue # 处理有效主机名的分支 c.send(bytes("print('"+ip+"')",'utf-8')) c.send(bytes('_socket.close()','utf-8')) c.close() # 新增:关闭客户端连接
二、跨机器无法连接的排查思路与解决
跨机器连接失败通常是网络或配置问题,咱们按优先级排查:
1. 先确认网络连通性
- 同局域网检查:让朋友先ping你的服务器IP(192.168.0.101),如果ping不通,说明两台机器不在同一个局域网(比如不在同一WiFi/子网),或者网络路由有问题。
- 端口开放检查:如果ping通,让朋友用
telnet 192.168.0.101 1234测试端口是否开放:- 若telnet连接失败,大概率是防火墙问题(即使你说没拦截,再仔细确认一遍):
- 你的Windows防火墙:进入「Windows Defender防火墙」→「高级设置」→「入站规则」,确保允许Python程序(或直接放行1234端口)接收来自局域网的连接。
- 朋友的电脑防火墙:检查是否允许出站连接到1234端口。
- 若telnet连接失败,大概率是防火墙问题(即使你说没拦截,再仔细确认一遍):
2. 确认服务器IP与绑定设置
- IP正确性:在服务器上运行
ipconfig查看IPv4地址,确认是不是192.168.0.101——很多局域网IP是动态分配的,可能已经变了,导致客户端连错地址。 - 绑定设置:你的服务器绑定
('', port)是对的,等价于绑定0.0.0.0,允许所有网卡访问,这部分没问题。如果朋友在外网(不在你的局域网),192.168.x.x是内网IP,无法直接访问,需要在路由器上做端口映射,或者使用公网IP/动态域名。
3. 代码逻辑的隐患(重要!)
你现在的实现方式是服务器发送可执行代码给客户端,让客户端exec执行,这种方式不仅极度不安全(客户端会执行服务器发送的任意代码),还可能因为编码、命令拆分的问题导致客户端无法正确执行,间接表现为连接异常。
建议改成数据交互模式,只传递数据而非执行代码,这样更稳定安全:
优化后的服务器端:
import socket from time import sleep def run_server(port=1234): print('Booting server...') print('|-|-|-', end='') sleep(0.05) server = socket.socket() server.bind(('', port)) print('|-|-|-', end='') sleep(0.05) server.listen(5) print('|-|-|', end='') sleep(0.05) print('\nServer is running and can be accessed now\n===============================================') while True: c, addr = server.accept() print('Received connection from: ', addr) # 发送提示消息,让客户端输入主机名 c.send(bytes("Welcome. Enter hostname to extract ip from: ", 'utf-8')) # 接收客户端发送的主机名 hostname = c.recv(1024).decode('utf-8').strip() try: ip = socket.gethostbyname(hostname) c.send(bytes(f"IP Address: {ip}", 'utf-8')) except: c.send(bytes("The hostname is either invalid or wasn't found", 'utf-8')) c.close() # 关闭客户端连接 run_server()
优化后的客户端:
import socket def run(): _socket = socket.socket() try: _socket.connect(('192.168.0.101', 1234)) # 接收服务器的提示消息 welcome_msg = _socket.recv(1024).decode('utf-8') print(welcome_msg) # 输入主机名并发送给服务器 hostname = input().strip() _socket.send(bytes(hostname, 'utf-8')) # 接收服务器返回的IP结果 result = _socket.recv(1024).decode('utf-8') print(result) except OSError as e: print(f"连接错误: {e}") finally: _socket.close() while True: run() print("\n按Enter键重新连接...") input()
这种模式彻底避免了exec带来的各种问题,连接稳定性也会大幅提升。
内容的提问来源于stack exchange,提问作者user15166425




