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

C语言消息队列传输数组实现及收发逻辑问题咨询

C语言System V消息队列传输数组及同步问题解答

核心问题定位

你当前代码无法传输数组的直接原因有三个:

  • 调用msgsnd时第三个参数只传入了sizeof(msg.msgtext),数组所在的内存块根本没有被写入消息队列
  • 接收端定义的消息结构体和发送端内存布局不一致,没有预留数组成员的内存空间,就算发了数组也会因为内存错位读不到
  • 代码里调用wait(NULL)但没有提前fork()子进程,该函数调用无实际作用,单进程内同时写收发逻辑不符合消息队列的进程间通信设计逻辑

疑问1:消息队列发送端与接收端是否需要分离实现?

必须分离实现。
System V消息队列是跨进程通信组件,设计目标就是在两个独立进程间传递数据。收发两端需要满足两个基本要求:

  • 两端定义的消息结构体内存布局完全一致:第一个成员固定为long类型的消息类型字段,后续自定义载荷(字符串、数组等)的类型、长度定义必须完全匹配,否则会出现数据读取错位
  • 两端通过同一个消息队列key(你代码里用的1234)访问同一条消息队列

疑问2:3次数组按序发送的同步逻辑实现

用消息类型做双向握手机制即可,不需要额外的锁或者信号量,逻辑简单可靠:

  • 约定消息类型规则:发送端发数组数据、结束通知都用类型1,接收端处理完一批数据后回传的ACK确认消息用类型2
  • 发送端流程:每发完1次数组,就阻塞等待接收端回传的类型2ACK消息,只有收到确认才启动下一批数组的生成和发送,从流程上保证发送顺序
  • 接收端流程:每收到1次类型1的数组消息,先判断是不是结束通知,不是的话完成数据读取处理后立刻回1个类型2的ACK
  • 收发同步场景下不要用IPC_NOWAIT非阻塞模式,直接用默认阻塞模式即可,避免空轮询或者读不到数据的误报错

数组传输实现逻辑

消息队列的收发本质是内存块拷贝,传输int数组和传输char字符串没有区别:只要把数组作为消息结构体的载荷成员,msgsnd时传入载荷部分的总长度(即结构体总长度减去第一个long类型消息字段的长度),接收端用匹配的结构体接收,就能直接读到数组内容。

可运行参考代码

发送端 sender.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/msg.h>
#include <time.h>

#define maxArr 100
#define MSG_KEY 1234

// 收发两端必须保持该结构体定义完全一致
struct msgbuffer {
    long msgtype;
    char msgtext[100];
    int arr[maxArr];
    int arr_len; // 额外传数组实际长度,方便接收端处理
};

// ACK消息结构体
struct ack_msg {
    long msgtype;
    char status[10];
};

int main() {
    int msgid = msgget(MSG_KEY, IPC_CREAT | 0600);
    if (msgid == -1) {
        perror("msgget failed");
        exit(1);
    }

    srand(time(NULL));
    struct msgbuffer data_msg;
    struct ack_msg ack;
    for (int batch = 0; batch < 3; batch++) {
        // 填充当前批次数据
        data_msg.msgtype = 1;
        sprintf(data_msg.msgtext, "第%d批数组", batch+1);
        data_msg.arr_len = 10; // 每批发10个随机数
        for (int i = 0; i < data_msg.arr_len; i++) {
            data_msg.arr[i] = rand() % 101;
        }
        // 发送数组:长度为结构体减去long msgtype的大小
        if (msgsnd(msgid, &data_msg, sizeof(data_msg) - sizeof(long), 0) == -1) {
            perror("msgsnd failed");
            exit(1);
        }
        printf("已发送第%d批数组,等待接收端确认...\n", batch+1);
        // 阻塞等ACK,收到才发下一批
        if (msgrcv(msgid, &ack, sizeof(ack) - sizeof(long), 2, 0) == -1) {
            perror("receive ack failed");
            exit(1);
        }
        printf("收到接收端确认,开始发送下一批\n");
    }

    // 发结束通知
    data_msg.msgtype = 1;
    strcpy(data_msg.msgtext, "finish");
    msgsnd(msgid, &data_msg, sizeof(data_msg) - sizeof(long), 0);
    return 0;
}

接收端 receiver.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/msg.h>

#define maxArr 100
#define MSG_KEY 1234

// 和发送端结构体完全一致
struct msgbuffer {
    long msgtype;
    char msgtext[100];
    int arr[maxArr];
    int arr_len;
};

struct ack_msg {
    long msgtype;
    char status[10];
};

int main() {
    int msgid = msgget(MSG_KEY, 0600);
    if (msgid == -1) {
        perror("msgget failed");
        exit(1);
    }

    struct msgbuffer data_msg;
    struct ack_msg ack;
    while (1) {
        // 阻塞收类型1的消息
        ssize_t ret = msgrcv(msgid, &data_msg, sizeof(data_msg) - sizeof(long), 1, 0);
        if (ret == -1) {
            perror("msgrcv failed");
            exit(1);
        }
        // 收到结束消息就退出
        if (strcmp(data_msg.msgtext, "finish") == 0) {
            printf("收到结束通知,退出接收\n");
            msgctl(msgid, IPC_RMID, NULL); // 删除消息队列
            break;
        }
        // 处理数组
        printf("收到%s,内容为:", data_msg.msgtext);
        for (int i = 0; i < data_msg.arr_len; i++) {
            printf("%d ", data_msg.arr[i]);
        }
        printf("\n");
        // 回ACK
        ack.msgtype = 2;
        strcpy(ack.status, "ok");
        msgsnd(msgid, &ack, sizeof(ack) - sizeof(long), 0);
    }
    return 0;
}

运行方式

分别编译两个文件,先启动接收端,再启动发送端即可看到按序传输的效果:

gcc receiver.c -o receiver
gcc sender.c -o sender
./receiver &
./sender

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 06:06:40