Python多线程Server to Client时间同步服务BrokenPipeError问题咨询
错误原因
BrokenPipeError本质是程序向已经被对端关闭的TCP连接写入数据触发的系统报错,你的代码存在以下几个问题直接导致该错误:
connectionSocket是全局变量,每次accept新连接都会覆盖这个变量的值,之前启动的客户端线程全部共用这个全局连接对象,旧连接被客户端关闭后,线程仍然往失效连接写数据直接触发报错serverSocket.listen(1)不需要放在循环内,该方法仅需要在服务端启动时调用1次,用于告知内核该套接字负责监听连接,重复调用无意义- 你的业务场景是客户端单次请求、单次接收响应后就主动关闭连接,但是服务端线程内用了
while True死循环不停接收发送数据,客户端关闭连接后服务端仍然在往该连接写数据 - 没有判断
recv的返回值,recv返回空字节时就代表客户端已经主动断开连接,此时应该直接终止线程释放资源
修复后的服务端代码
from threading import Thread import calendar import time from socket import * class ClientThread(Thread): def __init__(self, conn, ip, port): Thread.__init__(self) # 将连接对象存为线程实例属性,避免全局变量覆盖问题 self.conn = conn self.ip = ip self.port = port print(f"New server socket thread started for {ip} : {str(port)}") def run(self): # 单次请求响应场景不需要死循环,接收一次请求处理后即可关闭 data = self.conn.recv(2048) # recv返回空代表客户端已断开连接 if not data: self.conn.close() return ts = str(calendar.timegm(time.gmtime())) self.conn.send(ts.encode()) # 响应完成主动关闭连接,这里必须关闭 self.conn.close() serverPort = 12000 serverSocket = socket(AF_INET, SOCK_STREAM) serverSocket.bind(('', serverPort)) # listen放在循环外面,仅启动时调用一次即可 serverSocket.listen(5) threads = [] print('The server is ready to receive') while True: (connectionSocket, (ip, port)) = serverSocket.accept() # 将连接对象作为参数传入线程 newthread = ClientThread(connectionSocket, ip, port) newthread.start() threads.append(newthread) for t in threads: t.join()
关键修改说明
- 连接对象改为线程实例属性,解决全局变量被覆盖的问题
listen方法和服务启动提示都移到循环外,仅执行一次- 移除线程内死循环,适配单次请求响应的业务逻辑
- 增加连接断开检测逻辑,避免往失效连接写数据
内容的提问来源于stack exchange,提问作者p20xx
相关产品推荐
相关产品推荐

