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

Linux C环境下UNIX域套接字用iovec传多缓冲区仅首条被接收问题

UNIX域套接字多iovec传输异常问题排查

问题根因

经过对代码的核对,导致服务端无法正常接收第二个iovec内容的核心原因有以下几点:

  • 服务端msghdr结构体未初始化:客户端代码中对msghdr做了memset清零处理,但服务端定义struct msghdr msg后仅赋值了msg_iov和msg_iovlen两个字段,其余字段为栈上的随机垃圾值。如果msg_control、msg_flags等字段存在非法值,会导致内核在处理recvmsg时提前终止接收,或者错误判断接收缓冲区的有效范围。
  • 输出逻辑不符合recvmsg的行为规范:recvmsg不会修改传入的iovec结构体的iov_len字段,你输出的msg.msg_iov[0].iov_len值恒为初始化时的sizeof(buf)=16,并非实际写入的字节数。同时你直接用%s输出第二个缓冲区内容时,如果没有显式确认写入长度,若缓冲区未被写入数据、或者写入内容没有自动带\0终止符,就会输出空值。
  • 未校验收发的实际字节数:你没有打印sendmsg的返回值n和recvmsg的返回值len,无法确认所有数据是否已经完整发送和接收。如果使用的是SOCK_STREAM类型的UNIX域套接字,还可能出现半包问题,单次recvmsg只会读取部分数据。

修复方案

1. 服务端msghdr初始化

在服务端定义msghdr后立刻执行清零操作:

memset(&msg, 0, sizeof(msg));

2. 校验收发总长度

客户端发送后打印总发送字节数,确认等于两个缓冲区长度之和:

printf("total send bytes: %d, expected: %zu\n", n, sizeof(str1)+sizeof(str2));

服务端接收后打印总接收字节数,确认和发送长度匹配:

printf("total recv bytes: %d\n", len);

3. 修正输出逻辑

按实际接收长度输出第二个缓冲区的内容,避免依赖字符串自动终止符:

if (len > 0) {
    int first_buf_size = io[0].iov_len;
    // 第一个缓冲区实际写入的字节数,取总长度和第一个缓冲区大小的较小值
    int actual_first_len = len < first_buf_size ? len : first_buf_size;
    int actual_second_len = len - actual_first_len;
    printf("recv buf1: %.*s, actual write len: %d\nrecv buf2: %.*s, actual write len: %d\n",
        actual_first_len, (char*)io[0].iov_base, actual_first_len,
        actual_second_len, (char*)io[1].iov_base, actual_second_len);
}

4. 流式套接字适配

如果使用的是SOCK_STREAM类型的UNIX域套接字,需要封装循环接收逻辑,直到收齐预期长度的数据再处理,避免单次recvmsg读取不完整。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.11 23:18:00