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

通过iovec经Unix域套接字收发uint32_t数据接收值异常问题

问题根因

你拿到的随机值和字节类型转换没有任何关系,你打印的根本不是接收到的业务数据,而是iov_base这个指针本身存储的内存地址。
现代操作系统默认开启地址空间随机化(ASLR),每次程序运行时栈上分配的变量地址都会变化,加上你用%d(对应int类型)打印长度为8字节(64位系统下)的指针本身就属于未定义行为,自然每次运行都会得到毫无规律的随机数。

修复方案

1. 修正接收端缓冲区定义

不要用char数组硬接uint32_t类型数据,直接定义同类型变量作为接收缓冲区,从根源避免对齐问题:

// 接收端代码
uint32_t recv_request_id = 0;
struct iovec io = { 
    .iov_base = &recv_request_id, 
    .iov_len = sizeof(uint32_t) 
};
msg.msg_iov = &io;
msg.msg_iovlen = 1; // 必须显式设置iovec的数量,漏写会导致内核读错内存

2. 调用recvmsg后正确打印数据

iov_base只是指向缓冲区的指针,必须先完成数据接收、确认收满4字节后,直接打印缓冲区变量本身,不要打印指针:

ssize_t ret = recvmsg(sock_fd, &msg, 0);
if (ret == sizeof(uint32_t)) {
    // 正确打印接收到的uint32_t值
    printf("received request_id = %u\n", recv_request_id);
}

特殊情况:必须用char数组接收的处理方式

如果你因为业务逻辑必须用char dup[4]作为缓冲区,接收完成后需要做指针类型强转再解引用拿到数值,注意同主机Unix域套接字不需要做网络字节序转换,通信两端字节序完全一致:

// 收完数据后转换
uint32_t parsed_id = *(uint32_t*)dup;
printf("parsed request_id = %u\n", parsed_id);
额外注意事项
  • 真要打印指针地址时,必须用%p格式符,并且把指针强转为void*类型,用%d打指针是典型的未定义行为,32/64位系统下都会出现值错乱。
  • 如果你用的是SOCK_STREAM类型的Unix域套接字,和TCP一样是字节流语义,单次recvmsg调用不保证能收满你发的4字节,需要循环接收直到读满指定长度,避免半包问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.31 22:03:22