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

C++客户端用strtok拆分Python服务端坐标数据重复解析异常咨询

问题根因分析

你遇到的现象是多个问题共同导致的:

  • 接收参数错误:recv函数第三个参数传入了strlen(recvBuf),而recvBuf是未初始化的栈数组,strlen会随机读取内存直到遇到'\0',返回值完全不可控,导致大多数情况下无法完整读取服务端发来的新坐标数据,缓冲区残留的还是第一次接收的内容,所以分词结果始终不变。
  • 字符串无结束符:recv仅负责接收二进制字节,不会主动在接收内容末尾添加字符串结束符'\0',直接调用strcpy、strtok等字符串处理函数会读取到栈内存的垃圾数据,逻辑完全不可控。
  • strtok本身特性:该函数是不可重入函数,内部用静态变量存储上一次分词的位置,且会修改传入的字符串(将分隔符替换为'\0'),确实不符合你不修改原始缓冲区的需求。
  • 额外语法瑕疵:if (token != NULL);末尾多了一个多余的分号,属于无效空分支,不影响核心逻辑但建议删除。
修复方案

方案1:不使用strtok的C++更优实现(推荐)

该方案完全使用C++标准库实现分割,不会修改原始缓冲区,安全性和可维护性更高,完全满足你的需求:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>  
#include <Winsock2.h>  
#pragma comment(lib,"ws2_32.lib")
#pragma warning(disable:4996)
#include <iostream>
#include <sstream>
#include <string>
#include <vector>

using namespace std;

// 分割字符串函数,不修改原始输入
vector<string> split(const string& s, char delimiter) {
    vector<string> tokens;
    string token;
    istringstream tokenStream(s);
    while (getline(tokenStream, token, delimiter)) {
        if (!token.empty()) { // 过滤空串
            tokens.push_back(token);
        }
    }
    return tokens;
}

int main()
{
    const char delimitador = ',';
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;

    wVersionRequested = MAKEWORD(1, 1);
    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0) {
        return -1;
    }
    if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) {
        WSACleanup();
        return -1;
    }
    SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0);
    SOCKADDR_IN addrSrv;
    addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    addrSrv.sin_family = AF_INET;
    addrSrv.sin_port = htons(2070);
    connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));

    const char* baseCh = "hello";
    char recvBuf[50] = {0}; // 初始化缓冲区

    send(sockClient, baseCh, strlen(baseCh), 0);

    while (true)
    {
        // 修复接收逻辑:第三个参数传缓冲区可用长度,接收后补结束符
        int recvLen = recv(sockClient, recvBuf, sizeof(recvBuf) - 1, 0);
        if (recvLen <= 0) break; // 连接断开或出错则退出
        recvBuf[recvLen] = '\0'; // 补字符串结束符
        
        string originalBuf = recvBuf; // 原始缓冲区内容备份,不会被修改
        vector<string> tokens = split(originalBuf, delimitador);
        for (size_t i=0; i<tokens.size(); i++) {
            printf("Token %s\n", tokens[i].c_str());
        }

        send(sockClient, baseCh, strlen(baseCh), 0);
    }

    closesocket(sockClient);
    WSACleanup();
    getchar();
    return 0;
}

方案2:保留strtok的修复方式

如果一定要使用strtok,只需要修复接收逻辑即可,但注意该方式仍会修改你传入分词的缓冲区,所以要提前拷贝原始数据:

  1. 将recv的第三个参数改为sizeof(recvBuf)-1
  2. 接收后判断返回值,给recvBuf补'\0'
  3. 再拷贝到独立的expected数组中分词,不影响原始recvBuf的内容
额外优化建议(Python服务端)

你当前Python服务端发送的内容格式是"[1, 20, 25],",C端分割后得到的内容会包含[、空格、]等多余字符,建议服务端直接发送"1,20,25"格式的字符串,简化C端的解析逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 14:30:02