使用Socket与Threading实现客户端服务端通信时出错的解决求助
Socket多线程交互报错:WinError 10038 问题排查与解决
问题背景
尝试基于Socket和Threading实现客户端与服务端持续交互,服务端负责接收数据,客户端负责发送数据,但引入线程后出现发送数据错误。
服务端代码
import socket import threading import keyboard HOST = "127.0.0.1" PORT = 65432 def receive_function(pon): while True: det = pon.recv(1024) if det: print(f"\t\t\t\tFriend: {det.decode('utf-8')}") else: continue with socket.socket(socket.AF_INET,socket.SOCK_STREAM) as s: s.bind((HOST,PORT)) s.listen() print("LisTenING...") while True: conn, addr = s.accept() print(f"Connection Established with {addr} Device") x = threading.Thread(target=receive_function, args=(conn,)) x.start()
客户端代码
import socket import keyboard import threading from time import sleep HOST = "127.0.0.1" PORT = 65432 def send_data(s1): print("S1 is ",s1) s1.send(bytes("oi k xa", 'utf-8')) with socket.socket(socket.AF_INET,socket.SOCK_STREAM) as s: s.connect((HOST,PORT)) x = threading.Thread(target=send_data, args=(s,)) x.start()
错误信息
Exception in thread Thread-1: Traceback (most recent call last): File "E:\Python371\lib\threading.py", line 917, in _bootstrap_inner self.run() File "E:\Python371\lib\threading.py", line 865, in run self._target(*self._args, **self._kwargs) File "practice2.py", line 11, in send_data s1.send(bytes("oi k xa", 'utf-8')) OSError: [WinError 10038] An operation was attempted on something that is not a socket
问题原因
客户端使用with语句创建socket对象,with块执行完毕后会自动调用socket的close()方法关闭连接。而启动的线程是异步执行的,主线程的with块很快执行结束,socket被直接关闭销毁,此时线程里再尝试用这个已失效的socket对象发送数据,就会触发“操作非socket对象”的错误。
解决方案
方案1:移除with语句,手动管理socket生命周期
修改客户端代码,去掉with块,手动创建socket,确保线程执行完毕前socket不被回收:
import socket import keyboard import threading from time import sleep HOST = "127.0.0.1" PORT = 65432 def send_data(s1): print("S1 is ",s1) s1.send(bytes("oi k xa", 'utf-8')) # 如果需要持续发送数据,可在这里添加循环逻辑,比如监听键盘输入 # 最后不需要socket时手动关闭 # s1.close() # 手动创建socket,不使用with自动管理 s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.connect((HOST,PORT)) x = threading.Thread(target=send_data, args=(s,)) x.start() # 等待线程执行完毕,避免主线程提前退出导致socket被回收 x.join() s.close()
方案2:保留with语句,等待线程执行完毕
如果要保留with的自动资源管理特性,需要在with块内等待线程完成,确保socket在发送操作结束后才被关闭:
import socket import keyboard import threading from time import sleep HOST = "127.0.0.1" PORT = 65432 def send_data(s1): print("S1 is ",s1) s1.send(bytes("oi k xa", 'utf-8')) with socket.socket(socket.AF_INET,socket.SOCK_STREAM) as s: s.connect((HOST,PORT)) x = threading.Thread(target=send_data, args=(s,)) x.start() # 等待线程执行完成后,再退出with块 x.join()
额外优化:实现持续交互
如果需要客户端持续发送数据,可以修改send_data函数,添加循环逻辑监听输入:
def send_data(s1): while True: msg = input("输入要发送的消息(输入quit退出):") if msg.lower() == 'quit': break s1.send(bytes(msg, 'utf-8'))
内容的提问来源于stack exchange,提问作者LYrick Ness
相关产品推荐
相关产品推荐

