Python多线程TCP服务器无法正常关闭问题求助
问题分析
- 非守护线程阻止进程退出:创建的客户端线程默认是非守护线程,主线程执行
sys.exit(1)后,子线程仍会继续运行,导致服务器进程无法正常终止。 - 阻塞的
accept()调用无法退出:当服务器卡在s.accept()等待连接时,KeyboardInterrupt触发后,pass语句无法打破这个阻塞,后续的关闭逻辑无法及时执行。 recv_all未处理连接断开:代码中注释了连接断开的判断逻辑,当客户端主动断开时,conn.recv()返回空字节,recv_all会陷入无限循环,子线程无法正常退出。
修复方案
针对上述问题,对代码做以下修改:
1. 将客户端线程设为守护线程
在创建线程后,设置client_thread.daemon = True,这样主线程退出时,所有守护线程会自动终止。
2. 优雅打破accept()阻塞
在捕获KeyboardInterrupt时,先关闭监听socket,让s.accept()抛出异常并退出阻塞,确保后续关闭逻辑执行。
3. 修复recv_all的连接断开处理
取消注释连接断开的判断逻辑,当chunk为空时,抛出异常避免无限循环,同时在客户端处理函数中捕获该异常,确保子线程正常退出。
完整修复后的代码
#! /usr/bin/env python3 import sys, struct, socket, threading, logging HOST = "127.0.0.1" PORT = 52583 MSGLEN = 2048 def recv_all(conn,n): chunks = b'' bytes_recd = 0 while bytes_recd < n: chunk = conn.recv(min(n - bytes_recd, 1024)) if len(chunk) == 0: raise RuntimeError("socket connection broken") chunks += chunk bytes_recd = bytes_recd + len(chunk) return chunks def handle_client(conn, addr): print(f"Contacted by {addr}") with conn: try: while True: data = recv_all(conn, 4) input = struct.unpack("!i", data)[0] print(f"Received {input}") conn.sendall(struct.pack("!i",input)) print(f"Sent {input}") except RuntimeError: print(f"Client {addr} disconnected") def main(host=HOST, port=PORT): with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: try: s.bind((host, port)) s.listen() print(f"Server listening on {host}:{port}") while True: print("Waiting for a connection...") conn, addr = s.accept() client_thread = threading.Thread(target=handle_client, args=(conn, addr)) client_thread.daemon = True # 设置为守护线程 client_thread.start() except KeyboardInterrupt: print("Received shutdown signal, closing listening socket...") s.close() # 关闭监听socket,打破accept阻塞 except OSError: pass # 处理accept被打断后的异常 print("Server shutting down") sys.exit(0) if __name__ == "__main__": main()
额外说明
- 如果需要更优雅地关闭子线程,可维护一个全局退出标志,在
handle_client的循环中检查标志并主动退出,避免强制终止。 - 关闭监听socket后,
s.accept()会抛出OSError,捕获该异常可避免不必要的报错信息。
内容的提问来源于stack exchange,提问作者sansoneri
相关产品推荐
相关产品推荐

