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,只需要修复接收逻辑即可,但注意该方式仍会修改你传入分词的缓冲区,所以要提前拷贝原始数据:
- 将
recv的第三个参数改为sizeof(recvBuf)-1 - 接收后判断返回值,给
recvBuf补'\0' - 再拷贝到独立的
expected数组中分词,不影响原始recvBuf的内容
额外优化建议(Python服务端)
你当前Python服务端发送的内容格式是"[1, 20, 25],",C端分割后得到的内容会包含[、空格、]等多余字符,建议服务端直接发送"1,20,25"格式的字符串,简化C端的解析逻辑。
内容的提问来源于stack exchange,提问作者Pablo
相关产品推荐
相关产品推荐

