Python Socket程序阻塞:客户端无法退出循环的原因排查
问题分析与解决方案
咱们来一步步拆解你的问题,核心是两端都陷入了阻塞等待的僵局,谁都没先打破这个平衡:
客户端的阻塞根源
客户端发送完b'hello, world'后,立刻进入while True循环调用s.recv(1024)。要知道recv()是阻塞式调用:
- 如果服务端没发送数据,且连接没关闭,它会一直卡在这等数据
- 只有当服务端主动关闭连接(发送FIN包),
recv()才会返回空字节,触发break
但你的服务端既没给客户端发回复,也没主动关闭连接,所以客户端永远等不到data为空的时刻,自然跳不出循环。
服务端的逻辑错误
服务端的tr函数逻辑完全搞反了:
- 它先进入
while True循环调用sock.recv(1024),同样,只有客户端关闭连接,recv()才会返回空、跳出循环 - 然后才执行
sock.send(b'get it')——但此时客户端已经关闭连接了,这个发送操作毫无意义 - 你还注释掉了
sock.close(),即使循环结束,连接也没被正确关闭,客户端依然收不到结束信号
修复后的代码
客户端代码(优化后)
发送完数据后,主动关闭连接的写端(明确告诉服务端“我发完所有数据了”),然后等待服务端的回复,收到后直接退出循环:
import socket s = socket.socket() s.connect(('localhost', 6969)) s.send(b'hello, world') # 关闭写端,告知服务端已无数据发送 s.shutdown(socket.SHUT_WR) while True: data = s.recv(1024) if data: print(data) break # 收到回复后直接退出循环 else: break s.close()
服务端代码(优化后)
收到客户端的数据后立刻回复,回复完成后主动关闭连接,让客户端能感知到交互结束:
import socket, threading def tr(sock, addr): data = sock.recv(1024) if data: print(data) # 收到数据后立即回复客户端 sock.send(b'get it') # 处理完成后关闭连接,触发客户端的recv()结束阻塞 sock.close() s = socket.socket() s.bind(('localhost', 6969)) s.listen(5) while True: sock, addr = s.accept() t = threading.Thread(target=tr,args=(sock, addr)) t.start()
关键知识点梳理
socket.recv()是阻塞调用,除非连接关闭或者有数据到达,否则不会返回- 单次交互场景下,客户端发送完数据后可以用
shutdown(SHUT_WR)关闭写通道,明确告知服务端发送结束 - 服务端处理完请求后,一定要主动关闭连接,让客户端感知到交互终止
内容的提问来源于stack exchange,提问作者alwayslz
相关产品推荐
相关产品推荐

