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

使用clsocket开发TCP套接字时体素游戏坐标数据偏移问题求助

问题根因与修复方案

核心错误:违反TCP流式协议特性

  • TCP是无消息边界的字节流协议,你代码中默认单次Receive调用就能拿到完整的sizeof(glm::i64vec4)或者sizeof(chkpkt)大小的数据,是TCP开发的典型误区:底层网络会自动拆包、粘包,单次Receive可能只返回部分数据,也可能一次返回多包拼接的数据。
  • 服务端使用非阻塞模式,每次循环都会调用c->Receive(sizeof(glm::i64vec4)),如果上一次调用只收到了部分坐标数据,本次调用会直接覆盖接收缓冲区的内容,永远拼不出完整的坐标值,自然解析出来的坐标偏移、数据异常。你尝试用服务端返回的pos存储数据失败,本质就是服务端解析请求坐标时已经拿到了错误值,返回的chk.pos本身就是乱的。

修复方案:为每个连接维护独立接收缓冲区

每个客户端连接都单独绑定一个动态接收缓冲区,把每次Receive拿到的字节追加到缓冲区末尾,只有缓冲区长度大于等于单包大小的时候,才取出对应长度的数据解析,剩余数据留在缓冲区等待下次处理。
示例逻辑:

// 服务端每个客户端对应一个缓冲区,可改用结构体封装CActiveSocket和buf
std::deque<std::pair<CActiveSocket*, std::vector<uint8_t>>> clients;
// ... 接受连接逻辑不变
for (auto& client_pair : clients) {
    CActiveSocket* c = client_pair.first;
    std::vector<uint8_t>& recv_buf = client_pair.second;
    // 每次最多读4096字节到缓冲区
    int recv_len = c->Receive(4096);
    if (recv_len > 0) {
        auto data = (uint8_t*)c->GetData();
        recv_buf.insert(recv_buf.end(), data, data + recv_len);
        // 缓冲区够一个坐标包的长度再处理
        while (recv_buf.size() >= sizeof(glm::i64vec4)) {
            // 取出前sizeof的字节解析坐标
            glm::i64vec4 req_pos = *(glm::i64vec4*)recv_buf.data();
            // 删掉已经处理的字节
            recv_buf.erase(recv_buf.begin(), recv_buf.begin() + sizeof(glm::i64vec4));
            // 原有的打包回复逻辑不变
            chkpkt chk;
            chk.pos = req_pos;
            LOOP3D(chksize+2){
                chk.data(i,j,k).val = chk.pos.y*chksize+j;
                chk.data(i,j,k).id=0;
            }
            c->Send((uint8*)&chk,sizeof(chkpkt));
        }
    }
}

客户端也要做同样的缓冲区逻辑,攒够sizeof(chkpkt)的字节再解析,不要单次Receive就直接强转。

次要错误:结构体内存布局不一致

你直接把结构体强转为字节流发送,若客户端和服务端编译时的结构体对齐规则不同,会导致两边内存布局不一致,字段解析偏移。

修复方案:

  1. 优先手动序列化每个字段到字节数组,接收端按顺序反序列化,避免直接强转结构体指针;
  2. 也可以给结构体加编译器对齐指令,确保两边内存布局完全一致,比如GCC下给结构体加__attribute__((packed)),MSVC下加#pragma pack(1)。

其他隐患:非阻塞模式Send死循环

你服务端写了while (c->Send((uint8*)&chk,sizeof(chkpkt)) != sizeof(chkpkt)){},非阻塞模式下如果发送缓冲区满,Send会直接返回失败,这个死循环会直接占满CPU,甚至触发连接超时。非阻塞模式下Send返回不足长度时,要记录已发送的偏移量,等下次循环再发送剩余数据,不要原地死等。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 03:18:00