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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 10:43:26