Python Echo服务器在conn.recv(4)行无限阻塞问题求助
解决TCP Echo服务器卡在
conn.recv(4)的问题 你当前的代码出现死锁的核心原因是TCP是面向流的协议,没有天然的消息边界:
- 客户端发送完
b"Hello, world"后,未关闭连接的写通道,服务器的conn.recv(4)会一直阻塞,等待客户端发送更多数据 - 同时客户端进入
recv循环,等待服务器返回数据,两边互相等待,形成死锁
以下是两种可行的解决方案:
方案1:客户端发送完数据后关闭写端
修改客户端代码,发送完数据后调用s.shutdown(socket.SHUT_WR),明确告知服务器“发送已完成”,此时服务器的recv会返回空字节,触发后续的响应逻辑。
修改后的客户端代码:
import socket HOST = "127.0.0.1" PORT = 65432 print("Will try to send") with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((HOST, PORT)) s.sendall(b"Hello, world") # 关闭写端,告知服务器发送完毕 s.shutdown(socket.SHUT_WR) data = b"" while True: chunk = s.recv(1024) if not chunk: break data += chunk print(f"Received {data!r}")
服务器代码无需修改,此时服务器会在客户端关闭写端后,执行conn.sendall(old_data.encode())并退出循环。
方案2:定义消息边界(适配多消息场景)
如果需要服务器在同一个连接上处理多条消息,可通过消息长度前缀标记消息结束:先发送消息的字节长度,再发送实际内容,服务器先接收长度,再根据长度接收完整消息,避免无限阻塞。
修改后的服务器代码:
# echo-server.py import socket import struct HOST = "127.0.0.1" PORT = 65432 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind((HOST, PORT)) s.listen() print("Now listening") conn, addr = s.accept() with conn: print(f"Connected by {addr}") # 先接收4字节的消息长度(网络字节序) len_data = conn.recv(4) if not len_data: break msg_len = struct.unpack('!I', len_data)[0] # 按指定长度接收完整消息 full_data = b"" while len(full_data) < msg_len: # 每次最多接收4字节,剩余不足4字节时接收剩余量 chunk = conn.recv(min(4, msg_len - len(full_data))) if not chunk: break full_data += chunk # 返回完整消息 conn.sendall(full_data)
修改后的客户端代码:
import socket import struct HOST = "127.0.0.1" PORT = 65432 print("Will try to send") msg = b"Hello, world" # 把消息长度打包为4字节的网络字节序 msg_len = struct.pack('!I', len(msg)) with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((HOST, PORT)) # 先发送长度,再发送消息内容 s.sendall(msg_len + msg) data = b"" while True: chunk = s.recv(1024) if not chunk: break data += chunk print(f"Received {data!r}")
内容的提问来源于stack exchange,提问作者Gogiboy102
相关产品推荐
相关产品推荐

