Python Socket转发场景下第二次连接服务端触发Connection refused错误求助
问题根因定位
- 服务端逻辑缺失TCP服务的核心运行流程,第一次客户端连接处理完成后,整个服务进程就直接退出,对应端口没有进程持续监听新连接。
- 这完全匹配你遇到的异常现象:第一次连接时服务进程还在运行,能正常完成收发流程;第一次连接的客户端主动关闭socket后,服务端触发连接断开逻辑,直接退出程序,内核在收到第二次连接请求时,因为端口没有监听进程,直接返回连接拒绝,就触发了
ConnectionRefusedError: [Errno 111] Connection refused。
现有代码的具体问题拆解
- 完整TCP服务端必须满足的基础逻辑:预创建的监听socket要通过外层无限循环持续调用
accept()方法,每接收一个新的客户端连接请求,拿到对应的已连接套接字后,再单独处理这个连接的收发逻辑;单个连接处理完成后,必须回到监听套接字的accept()步骤,等待下一个新连接。你当前的代码仅调用了一次accept(),拿到第一个客户端的连接套接字后就全程处理这一个连接,完全缺失外层的监听循环。 - 异常处理逻辑存在缺陷:
- 仅捕获了
recv()方法触发的ConnectionResetError,如果捕获异常时data保留了之前的旧值,后续执行sendall()时会向已经断开的连接发送数据,触发未捕获的BrokenPipeError,直接导致服务端崩溃退出。 - 当
recv()返回空字符串(代表客户端正常断开连接)时,直接执行break跳出当前循环,没有任何代码能回到监听逻辑等待新连接。
- 仅捕获了
- 你把已连接套接字
csockid放在最外层的with语句块中,当这个连接的处理逻辑结束时,块执行完成会自动退出,没有任何后续逻辑能接住新的连接请求。
修复方案
- 调整服务端的循环结构,拆分为两层独立的执行逻辑:
- 外层无限循环用预创建的监听socket持续调用
accept(),等待新的客户端连接 - 内层循环专门处理当前已建立连接的收发逻辑,连接断开后关闭当前连接的套接字,回到外层循环继续等待下一个连接
- 外层无限循环用预创建的监听socket持续调用
- 扩大异常捕获范围,把
sendall()可能触发的连接断开异常也纳入捕获逻辑,避免服务端因为未捕获的异常直接崩溃 - 连接断开时仅关闭当前客户端的连接套接字,不能触发整个服务进程的退出
修正后的服务端参考代码:
# 预创建的监听socket,提前完成bind、listen操作,全程不手动关闭 while True: # 外层循环:持续等待新的客户端连接 csockid, client_addr = listen_sock.accept() try: # 内层循环:处理当前连接的收发逻辑 while True: try: data = csockid.recv(512) # 收到空数据代表客户端正常断开连接 if not data: break data = data.decode('utf-8').strip() csockid.sendall(data.encode('utf-8')) except (ConnectionResetError, BrokenPipeError): # 捕获连接断开类的异常,避免服务端崩溃 break finally: # 无论正常断开还是异常断开,都关闭当前连接的套接字 csockid.close()
内容的提问来源于stack exchange,提问作者h1smajesty
相关产品推荐
相关产品推荐

