connection.recv() 阻塞时无法感知对方异常断连,应改用 poll(timeout) 轮询判断可读状态;listener.accept() 返回的 connection 不可跨进程传递,因无法序列化内核句柄,子进程需通过 client 重建连接;authkey 必须为 ≥16 字节的 bytes;send() 不适合传输大对象,应改用 shared_memory 等机制。

Connection.recv() 阻塞时怎么知道对方断连了
默认情况下 Connection.recv() 会一直卡住,直到收到数据或连接被对方关闭。但“关闭”不等于“断连”——如果对方进程崩溃、kill -9 或网络中断,本端可能永远等不到 EOF,也就不会抛出异常。
解决办法是用 Connection.poll() 加超时轮询,而不是裸调 recv():
while True:
if conn.poll(1.0): # 等最多 1 秒
try:
data = conn.recv()
break
except EOFError:
print("对方已关闭连接")
break
else:
# 超时,可检查 conn.closed 或做心跳逻辑
if conn.closed:
break-
poll(timeout)返回True表示有数据可读(或连接已关闭),False表示超时 - 即使对方已 exit,
poll()在多数系统上仍能较快返回False,比盲等安全得多 - 不要依赖
conn.closed实时反映状态——它只在本地显式调用close()后才为True,对方挂掉时这个值不变
Listener.accept() 返回的 Connection 为什么不能跨进程传递
你不能把一个 Connection 对象 pickle 后发给子进程,再在那边用——它底层绑定了文件描述符和操作系统句柄,pickle 只能序列化引用,无法复制内核资源。
常见错误场景:父进程创建 Listener,accept() 得到 conn,然后用 multiprocessing.Process(target=handler, args=(conn,)) 传进去,运行时报 TypeError: cannot pickle '_multiprocessing.Connection' object。
立即学习“Python免费学习笔记(深入)”;
BJXSHOP购物管理系统是一个功能完善、展示信息丰富的电子商店销售平台;针对企业与个人的网上销售系统;开放式远程商店管理;完善的订单管理、销售统计、结算系统;强力搜索引擎支持;提供网上多种在线支付方式解决方案;强大的技术应用能力和网络安全系统 BJXSHOP网上购物系统 - 书店版,它具备其他通用购物系统不同的功能,有针对图书销售而进行开发的一个电子商店销售平台,如图书ISBN,图书目录
- 正确做法是让子进程自己连回去:父进程把
Listener.address和认证码(authkey)传过去,子进程用Client(address, authkey=...)重建连接 - 或者用
multiprocessing.Pipe()+spawn启动方式,在 fork 前就建好管道,这样子进程能继承句柄(仅限 Unix,且需注意 Windows 不支持 fork) - Windows 下尤其要小心:
spawn模式下所有对象都得重新导入,Connection绝对不能作为参数传入
authkey 长度不够或类型不对导致 ConnectionRefusedError
用 Client() 连 Listener 时如果报 ConnectionRefusedError: [Errno 111] Connection refused,大概率不是端口问题,而是认证失败被服务端静默拒绝。
authkey 必须是 bytes 类型,且长度建议 ≥ 16 字节;太短(比如 b"123")或用字符串(如 "abc")都会导致握手失败。
- 错误写法:
Client(addr, authkey="mykey")→ 字符串,自动编码可能出错 - 正确写法:
Client(addr, authkey=b"my_very_secret_key_2024") - 如果用
Listener(authkey=...)指定了 key,所有Client必须用完全相同的bytes对象,大小写、长度、编码一个都不能差 - 调试时可在服务端加
print("Auth key received:", conn._handle)(不推荐生产用),但更稳的方式是统一用os.urandom(32)生成并共享
Connection.send() 传大对象慢甚至卡死
Connection.send() 底层走的是 pickle + 管道/套接字,不是零拷贝。传一个几百 MB 的 numpy 数组,会先全量序列化进内存,再分块写入,极易触发 GC 停顿或 OOM。
这不是 bug,是设计使然——multiprocessing.connection 适合传控制指令、小结构体、任务 ID,不适合搬运大数据。
- 传大数组优先用
multiprocessing.shared_memory(Python 3.8+)或numpy.memmap,只传名字/路径和 shape - 如果必须用
send(),确保对象已用__getstate__剥离非必要字段,避免意外带入大缓存或闭包 - 注意 Windows 下默认使用匿名管道,缓冲区小(约 64KB),大 payload 容易阻塞;Unix 下用 socket 更稳,但仍有 pickle 开销
真正难处理的从来不是怎么连上,而是连上之后——谁负责关、什么时候关、断了怎么重试、数据边界在哪、pickle 兼容性怎么控。这些细节不写进日志,就只能靠 kill -USR1 看堆栈猜。









