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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.18 10:45:00