You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:51:17