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

TCP客户端未等待recv直接发送全部数据的问题求助

TCP客户端服务端时序问题分析与修复方案

核心问题定位

  1. 代码缩进错误:客户端代码里的sock.connect及后续收发逻辑没正确缩进在with代码块内,导致这些代码根本没在socket上下文里执行,相当于直接跳过所有recv操作,一次性发送了全部数据。
  2. 收发时序不匹配:服务端的步骤和客户端的接收/发送动作没有严格对应,加上未校验recv返回值,无法确保服务端响应已被正确接收。
  3. 未处理流式协议边界:TCP是流式协议,recv(1024)不一定能拿到完整消息,当前代码没做消息完整性校验,容易出现解析错误。

修复步骤

1. 修正客户端代码(缩进+校验)

确保所有socket操作都在with块内,阻塞模式下recv才会生效,同时添加响应校验:

freq = 8
key = 1
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
    sock.connect((self.HOST, self.PORT))
    progress_callback.emit(1)
    
    # 初始化消息:发→收
    sock.sendall(bytes(TcpMsgs.INIT_MSG.value, "UTF-8"))
    resp = str(sock.recv(1024)).strip().lower()
    # 校验服务端返回的空格响应
    if resp != " ":
        raise RuntimeError("初始化响应异常")
    
    progress_callback.emit(2)
    # 频率消息:发→收
    sock.sendall(bytes(TcpMsgs.FREQ_MSG.value + str(freq), "UTF-8"))
    resp = str(sock.recv(1024)).strip().lower()
    if resp != "ok":
        raise RuntimeError("频率设置响应异常")
    
    progress_callback.emit(3)
    # 密钥长度消息:发→收
    sock.sendall(bytes(TcpMsgs.KEY_LEN_MSG.value + str(key), "UTF-8"))
    
    progress_callback.emit(4)
    # Beacon消息:发→收
    sock.sendall(bytes(TcpMsgs.BEACON_MSG.value, "UTF-8"))
    resp = str(sock.recv(1024)).strip().lower()
    if resp != "ok":
        raise RuntimeError("Beacon响应异常")
    
    progress_callback.emit(5)
    # 等待Beacon确认响应
    resp = str(sock.recv(1024)).strip().lower()
    if resp != "ok":
        raise RuntimeError("Beacon确认响应异常")
    
    # 接收服务端最终的随机数组
    rand_data = sock.recv(1024)
    rand_array = pickle.loads(rand_data)

2. 修正服务端代码(时序+异常处理)

严格对应客户端的收发步骤,同时处理recv返回空(客户端断开)的情况:

import pickle
import random

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    print("OPENING SOCKET")
    s.bind(("", self.__port))
    s.listen()
    conn, addr = s.accept()
    with conn:
        progress_callback.emit(1)
        print("Connected by:", addr)
        
        # 接收初始化消息
        init_msg = conn.recv(1024)
        if not init_msg:
            print("客户端在初始化阶段断开")
            break
        progress_callback.emit(2)
        conn.sendall(bytes(" ", "UTF-8"))
        
        # 接收频率消息并回复
        freq_msg = conn.recv(1024)
        if not freq_msg:
            break
        freq = float(str(freq_msg).split(":")[1])
        progress_callback.emit(3)
        self.__dataDictionary.update({BobVars.FREQ_DICT_KEY.value: freq})
        conn.sendall(bytes("ok", "UTF-8"))
        
        # 接收密钥长度消息
        key_len_msg = conn.recv(1024)
        if not key_len_msg:
            break
        key_len = int(str(key_len_msg).split(":")[1])
        progress_callback.emit(4)
        self.__dataDictionary.update({BobVars.KEY_LEN_DICT_KEY.value: key_len})
        
        # 接收Beacon消息并回复
        beacon_msg = conn.recv(1024)
        if not beacon_msg:
            break
        progress_callback.emit(5)
        conn.sendall(bytes("ok", "UTF-8"))
        
        # 等待内部Beacon确认
        while self.__waitFlag:
            pass
        progress_callback.emit(6)
        # 发送Beacon确认响应
        conn.sendall(bytes("ok", "UTF-8"))
        self.__waitFlag = not self.__waitFlag
        
        # 发送随机数组
        rand_array = pickle.dumps([random.randint(0,1) for _ in range(key_len)])
        conn.sendall(rand_array)

3. 额外优化建议

  • 消息边界处理:TCP是流式协议,建议给每条消息加长度前缀或结束标记(比如换行符),循环接收直到拿到完整消息,避免因消息拆分导致解析错误。
  • 异常捕获:在客户端和服务端添加try-except块,捕获ConnectionResetError、TimeoutError等异常,避免程序直接崩溃。
  • 阻塞模式验证:如果修复后还是出现跳过recv的情况,检查是否有其他线程干扰progress_callback的执行,导致代码逻辑异步执行。

内容的提问来源于stack exchange,提问作者Guillermo Fuentes

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 20:36:23