Python Socket双向通信代码挂死问题及回复必要性咨询
Socket双向通信挂死问题解答
双向挂死的根因
- 服务端阻塞:TCP是字节流协议,不存在一次
send对应一次recv的绑定规则。客户端总共发送了6字节数据b"123456",服务端每次调用conn.recv(2)最多读取2字节,循环3次就能读完所有已发送数据。读完后服务端仍会执行下一次conn.recv(2),此时客户端没有新数据发送、也没有关闭连接,阻塞模式的recv会让服务端永久卡在这里等待新数据。 - 客户端阻塞:客户端发完数据后直接调用
cs.recv(1024),阻塞等待服务端返回数据。注释掉回复逻辑时,服务端一直卡在recv步骤,永远不会执行后续的conn.sendall(b"Finished"),两边进入死等状态。
取消注释回复OK后正常运行的原因
开启conn.sendall(b"OK")逻辑后,服务端第一次收到2字节就会给客户端返回OK,客户端的recv收到数据后结束等待,继续执行cs.close()关闭连接。客户端关闭连接后,服务端下一次调用conn.recv(2)会收到空字节,触发if not data: break跳出循环,整个流程正常结束。
服务端即时回复不是强制要求
核心是要明确请求边界,避免两端死等,你可以选择以下任意一种方案替代即时回复:
- 约定请求长度:比如前4字节存储请求总长度,服务端收满指定长度的数据后,再统一返回响应
- 约定结束标记:比如请求末尾以
\r\n或者自定义特殊字符作为结束符,服务端读到结束符就停止接收请求,再返回响应 - 客户端发完请求后调用
cs.shutdown(socket.SHUT_WR)关闭写端:此时服务端recv会收到空字节,感知到客户端已无数据发送,处理完成后再返回响应即可
代码小瑕疵
服务端接受连接后的打印逻辑有误,print(f"Accepted connection from {HOST}:{PORT}")打印的是服务端自身监听地址,应该修改为打印对端地址:print(f"Accepted connection from {addr[0]}:{addr[1]}")
内容的提问来源于stack exchange,提问作者torayeff
相关产品推荐
相关产品推荐

