Python Tkinter GUI聊天室点击connect触发WinError10038错误如何解决
报错根因
- 你在客户端代码初始化阶段就直接启动了
receive和write两个后台线程,此时用户还没点击connect按钮建立连接,线程内调用client.recv()会直接触发异常,执行异常分支里的client.close()把套接字关闭。等你点击connect按钮调用client.connect()时,操作的已经是被关闭的无效套接字,就会抛出10038错误。 - 另外你当前的昵称获取逻辑是窗口刚启动就执行
nickname = entry3.get(),此时用户还没输入昵称,拿到的永远是空字符串,不符合业务逻辑。
修复方案
调整逻辑顺序:
- 套接字初始化、接收/发送线程启动都挪到connect函数内,仅在用户点击连接、填写完所有参数后再执行
- 昵称获取也放在connect函数内,等用户输入完成后再读取
- 增加重复点击连接的防护逻辑
- 增加连接异常捕获逻辑
修复后的完整客户端代码如下:
import socket import threading import tkinter as tk root = tk.Tk() canvas1 = tk.Canvas(root, width=600, height=600) canvas1.pack() # IP输入框 entry1 = tk.Entry(root) canvas1.create_window(200, 140, window=entry1) # 端口输入框 entry2 = tk.Entry(root) canvas1.create_window(200, 240, window=entry2) # 昵称输入框 entry3 = tk.Entry(root) canvas1.create_window(200, 340, window=entry3) client = None connected = False nickname = "" def connect(): global client, connected, nickname, receive_thread, write_thread if connected: return # 读取用户输入的参数 ip = entry1.get() port = entry2.get() nickname = entry3.get() if not ip or not port or not nickname: print("请填写完整的IP、端口和昵称") return try: # 初始化套接字并发起连接 client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect((ip, int(port))) connected = True print("连接成功") # 连接成功后再启动收、发线程 receive_thread = threading.Thread(target=receive, daemon=True) receive_thread.start() write_thread = threading.Thread(target=write, daemon=True) write_thread.start() except Exception as e: print(f"连接失败:{e}") if client: client.close() connected = False button1 = tk.Button(text='connect', command=connect) canvas1.create_window(200, 180, window=button1) def receive(): global connected while connected: try: message = client.recv(1024).decode('ascii') if message == 'NICK': client.send(nickname.encode('ascii')) else: print(message) except: print("连接断开") break connected = False client.close() def write(): global connected while connected: try: content = input("") message = f'{nickname}: {content}' client.send(message.encode('ascii')) except: print("连接断开") break connected = False client.close() root.mainloop()
注:代码中给线程加了daemon=True参数,保证关闭窗口时后台线程会同步退出,不会残留进程。
内容的提问来源于stack exchange,提问作者Elias Havas
相关产品推荐
相关产品推荐

