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

如何将recvfrom()接收的数据存入结构体以避免UDP短包写入多余字节?

问题原因分析
  • 核心问题:写入操作固定使用data数组的总长度1400字节作为写入量,没有区分每个数据包的实际有效数据长度。PSG结构体头部固定长度为24字节(2个uint64_t + 2个uint32_t),当recvfrom返回的接收总长度bytesrecv小于1424时,data数组中只有bytesrecv - 24字节是实际收到的有效数据,剩余部分是结构体未被覆盖的内存脏数据,这部分数据被写入文件就会导致末尾出现多余字节。
  • 逻辑冗余问题:当前代码每次收到一个包就对整个vector排序并全量写入文件,会导致文件内容重复写入,建议调整为收完全部数据包后再统一排序写入。
解决方案

1. 新增字段记录每个包的有效数据长度

新增封装结构体,将PSG包和对应有效数据长度绑定存储,避免丢失接收长度信息:

#pragma pack(push, 1)
struct PSG
{
    uint64_t id;
    uint64_t size;
    uint32_t type;
    uint32_t count;
    uint8_t data[1400];
};
#pragma pack(pop)

// 封装结构,存储PSG包和对应有效数据长度
struct PSGEntry {
    PSG pkg;
    uint32_t valid_data_len;
};

2. 收包时增加合法性校验,计算有效长度

收包后先校验包完整性,再计算本次包的有效数据长度存入结构体,写入时使用有效长度替代固定的数组长度:

std::vector<PSGEntry> psg_vector;
while(1) {
    PSG psg;
    int bytesrecv = recvfrom(m_sock, &psg, sizeof(PSG), 0, (sockaddr*)nullptr, nullptr);
    if (bytesrecv < 0) {
        perror("recvfrom");
        close(m_sock);
        return -1;
    }
    // 非法包校验:至少要收到完整头部才处理
    const uint32_t header_len = offsetof(PSG, data);
    if (bytesrecv < header_len) {
        continue;
    }
    // 计算有效data长度,不超过data数组最大容量
    uint32_t valid_len = std::min(
        static_cast<uint32_t>(bytesrecv - header_len),
        static_cast<uint32_t>(sizeof(psg.data))
    );
    psg_vector.push_back({psg, valid_len});
}

// 所有包收完后统一排序、写入
sort(psg_vector.begin(), psg_vector.end(), [](const auto& lhs, const auto& rhs) {
    return lhs.pkg.count < rhs.pkg.count;
});
for (const auto& entry : psg_vector) {
    file.write(
        reinterpret_cast<const char*>(entry.pkg.data),
        entry.valid_data_len
    );
}

额外说明

如果你的业务场景需要边收边写,可以在每次收到新包后,只写入新的单个包数据,避免全量重复写入,降低IO开销。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 08:36:06