You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 16:21:01