TCP socket传输含字符串成员的C++类时出现乱码如何解决?
问题根本原因
- 你类中的
playerId是const char*指针类型,类实例本身仅存储字符串的内存地址,不会存储实际的字符串内容。你调用send时仅发送了类本身的内存(PacketType的值 + 4/8字节的地址值),根本没有把"maxrskiy"的实际字符串内容发送到对端。 - 服务端的指针地址仅在服务端当前进程空间有效,客户端拿到这个地址属于无意义的野指针,读取对应内存的内容自然是乱码。
- 此外你的代码还存在两个低级错误:
send调用时强转(char*)packet应为(char*)&packet,需要取类实例的地址;客户端用LeavePlayerPacket类型接收JoinPlayerPacket类型的包,类型完全不匹配。
可行解决方案
方案1:改用固定长度字符数组存储字符串(最简单快速)
将类内的指针替换为固定长度的字符数组,让字符串内容直接存在类的内存空间内,不需要单独处理序列化:
class JoinPlayerPacket { public: PacketType type; char playerId[64]; // 固定长度,设置为足够容纳业务中最长的playerId即可 };
服务端发送逻辑:
JoinPlayerPacket packet; packet.type = JOIN_PLAYER; // 拷贝字符串到数组,确保不会越界且末尾带\0 strncpy(packet.playerId, "maxrskiy", sizeof(packet.playerId) - 1); packet.playerId[sizeof(packet.playerId) - 1] = '\0'; send(sock, (char*)&packet, sizeof(packet), 0);
客户端接收逻辑:
JoinPlayerPacket buf; // 必须和发送端的包类型完全一致 int bytesReceived = recv(sock, (char*)&buf, sizeof(buf), 0); if (bytesReceived == sizeof(buf)) { cout << buf.playerId << endl; }
优点是实现零额外复杂度,不需要处理序列化逻辑;缺点是有空间浪费,且字符串长度不能超过预设的数组长度。
方案2:自定义序列化格式(通用灵活,工业界常用)
采用「长度+内容」的自定义序列化规则,支持任意长度的字符串,没有空间浪费:
服务端发送逻辑:
const char* playerId = "maxrskiy"; uint32_t idLen = strlen(playerId); // 计算总发送长度:包类型长度 + 字符串长度字段长度 + 字符串实际长度 uint32_t totalLen = sizeof(PacketType) + sizeof(idLen) + idLen; char* sendBuf = new char[totalLen]; // 依次把内容拷贝到发送缓冲区 char* ptr = sendBuf; memcpy(ptr, &type, sizeof(PacketType)); ptr += sizeof(PacketType); memcpy(ptr, &idLen, sizeof(idLen)); ptr += sizeof(idLen); memcpy(ptr, playerId, idLen); // 发送数据 send(sock, sendBuf, totalLen, 0); delete[] sendBuf;
客户端接收逻辑:
PacketType type; uint32_t idLen; // 先读固定长度的包头字段 recv(sock, (char*)&type, sizeof(type), 0); recv(sock, (char*)&idLen, sizeof(idLen), 0); // 按长度读取字符串内容 char* playerId = new char[idLen + 1]; recv(sock, playerId, idLen, 0); playerId[idLen] = '\0'; cout << playerId << endl; delete[] playerId;
优点是灵活无浪费,支持扩展任意复杂的成员字段;缺点是需要自行处理序列化、反序列化逻辑,且要注意TCP流协议的粘包、半包问题,生产环境需要确保收够完整长度的包再解析。
方案3:使用现成序列化库
如果项目复杂度较高,可以直接使用Protobuf、FlatBuffers这类成熟的序列化库,自动完成复杂结构的序列化、反序列化逻辑,还支持跨平台、跨语言交互。
内容的提问来源于stack exchange,提问作者maxrskiy
相关产品推荐
相关产品推荐

