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

C++服务端与Python客户端Hangman游戏的send()/recv()同步问题

修复方案

问题根源

你遇到的两个异常本质是TCP流协议的数据边界未处理和服务端未检测连接断开状态导致的:

  1. TCP是无边界的流协议,send()/recv()不保证一次发送/接收完整消息,若没有明确的消息分隔符,客户端可能把多次发送的内容混在一起读取,或者读取不完整,导致后续逻辑阻塞。
  2. 客户端提前关闭后,服务端的recv()会返回0(表示连接断开),但如果没检测这个状态,会继续用之前缓存的输入重复执行逻辑。

1. 给通信消息添加明确的边界标记

所有发送的消息(猜词模板、结果提示、胜负消息)末尾追加换行符\n,两端按行读取,确保每次处理完整的单条消息。

C++服务端修改

发送消息时统一加换行符:

// 发送初始猜词模板
std::string init_msg = current_template + "\n";
send(client_socket, init_msg.c_str(), init_msg.size(), 0);

// 发送结果+更新后的模板
std::string result_msg = "正确!\n" + current_template + "\n";
send(client_socket, result_msg.c_str(), result_msg.size(), 0);

// 发送胜负终结消息
std::string end_msg = "你赢了!答案是:" + answer + "\n";
send(client_socket, end_msg.c_str(), end_msg.size(), 0);

接收客户端输入时,去掉换行符,只取有效字母:

char buffer[1024] = {0};
ssize_t recv_len = recv(client_socket, buffer, sizeof(buffer)-1, 0);
if (recv_len <= 0) {
    // 客户端断开,直接关闭socket并退出线程
    close(client_socket);
    return;
}
// 截断换行符,取第一个有效字符
std::string input(buffer);
size_t newline_pos = input.find('\n');
if (newline_pos != std::string::npos) {
    input = input.substr(0, newline_pos);
}
char guess = toupper(input.empty() ? ' ' : input[0]);

Python客户端修改

用socket.makefile()按行读取消息,替代直接recv(),自动处理换行符:

import socket

client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(("localhost", 12345))
# 用文件对象按行读取,自动处理换行符边界
file_obj = client_socket.makefile('r')

while True:
    # 读取完整消息(直到换行符)
    msg = file_obj.readline().strip()
    if not msg:
        # 服务端断开连接
        break
    print(msg)
    # 判断是否结束游戏
    if "赢了" in msg or "输了" in msg:
        break
    # 发送用户输入,末尾加换行符,用sendall确保发送完整
    guess = input("请输入一个字母:").strip().upper()
    client_socket.sendall((guess + "\n").encode('utf-8'))

file_obj.close()
client_socket.close()

2. 服务端添加连接断开检测

在客户端处理线程的循环中,每次调用recv()后必须检查返回值:

  • recv_len == 0:客户端正常断开,关闭socket并退出线程
  • recv_len == -1:通信错误,同样关闭socket退出

修改C++服务端的线程逻辑:

void handle_client(int client_socket) {
    std::string answer = generate_random_word();
    std::string current_template(answer.size(), '_');
    int remaining_attempts = 6;

    // 发送初始模板
    std::string init_msg = current_template + "\n";
    send(client_socket, init_msg.c_str(), init_msg.size(), 0);

    while (true) {
        char buffer[1024] = {0};
        ssize_t recv_len = recv(client_socket, buffer, sizeof(buffer)-1, 0);
        
        // 核心:检测连接断开或错误
        if (recv_len <= 0) {
            close(client_socket);
            return;
        }

        // 处理输入、验证字母、更新模板的逻辑...
        
        // 发送结果后,检查是否胜负已分,是则关闭连接退出
        if (current_template == answer || remaining_attempts <= 0) {
            send(client_socket, end_msg.c_str(), end_msg.size(), 0);
            close(client_socket);
            return;
        }
    }
}

验证修复效果

  1. 客户端第二次接收模板后,会正常提示输入字母,不再出现阻塞
  2. 提前关闭客户端,服务端线程会立即检测到连接断开,停止后续逻辑,不会重复处理旧输入

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 05:53:22