进程通信之消息队列

消息队列

消息队列是一种进程间通信(IPC)机制,允许进程以消息的形式传递数据。它通过在内核中维护的队列实现,提供了异步通信的能力。消息队列由键值唯一标识,支持一个或多个进程之间的数据传输。

相关函数

msgget

  • 功能:创建或获取一个消息队列
  • 函数原型:
int msgget(key_t key, int msgflg);
  • 参数:
    • key:消息队列的键即标识,可以通过 ftok 生成
    • msgflg:访问权限。
      • IPC_CREAT —— 如果 key 不存在,则创建
      • IPC_EXCL —— 如果 key 存在,则返回失败
  • 返回值:成功返回消息队列标识符(非负整数),失败返回 -1

msgsnd

  • 功能:向消息队列发送消息
  • 原型:
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
  • 参数:
    • msqid:消息队列标识符,也就是上述创建的返回值
    • msgp:指向消息的指针,是个结构体,但需要自己手动定义(放下面了)
    • msgsz:消息正文的大小(不包括消息类型)
    • msgflg:操作标志(如 IPC_NOWAIT 非阻塞发送,即如果包含此选项,则消息队列满时,不发送该消息,立即返回 -1。反之,如果不包含此选项,则消息队列满时,挂起本进程,直到消息队列由空间可用。)
// 结构体的定义
struct message {
    long msg_type;       // 消息类型,必须为 long 类型即 long int
    char msg_text[100];  // 消息正文,数组大小自定义
};
  • 返回值:成功返回 0,失败返回 -1

msgrcv

  • 功能:从消息队列接收消息
  • 函数原型:
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
  • 参数:
    • msqid:消息队列标识符,即创建消息队列时候的函数返回值
    • msgp:存储接收到的消息的指针(上面 msgsnd 已介绍)
    • msgsz:期望接收的消息正文大小
    • msgtyp:消息类型(0 表示接收任意类型)
      • 0:忽略消息类型,从消息队列中接收队列中的第一条消息(按照队列的 FIFO 顺序)
      • 大于 0:从消息队列中接收类型为 msg_type 的第一条消息,如果队列中没有匹配的消息,进程会阻塞,直到符合条件的消息到达(或设置了非阻塞标志)
      • 小于 0:从消息队列中接收类型值小于等于 |msg_type|(绝对值)的消息,选择类型值小于等于 |msg_type| 且优先级最高的消息(类型值越小,优先级越高)
    • msgflg:操作标志(如 IPC_NOWAIT 非阻塞接收,上述 msgsnd 已经介绍)
  • 返回值:成功返回消息队列标识符(非负整数),失败返回 -1

msgctl

  • 功能:控制和管理消息队列
  • 原型:
int msgctl(int msqid, int cmd, struct msqid_ds *buf);`
  • 参数:
    • msqid:消息队列标识符,即创建消息队列时候的函数返回值
    • cmd:控制命令,指定要对消息队列执行的操作
      • IPC_STAT:获取消息队列的当前状态
      • IPC_SET:设置消息队列的属性
      • IPC_RMID:从系统中删除消息队列
    • buf:指向一个 msqid_ds 结构的指针,用于传递或接收消息队列的信息
      • IPC_STAT:由内核填充 buf,包含消息队列的当前状态,然后作为传出参数,用户可以进行读取数据查看消息队列状态
      • IPC_SET:用户手动填充 buf 中的部分字段,将其作为传入参数,修改消息队列的属性
      • IPC_RMID:此参数可以为 NULL,因为该操作不需要 buf
  • 返回值:成功返回 0,失败返回 -1

示例

发送方

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

// 定义消息结构
struct msgbuf {
    long msg_type;       // 消息类型
    char msg_text[256];  // 消息内容
};

int main() 
{
    key_t key;
    int msqid;
    struct msgbuf msg;

    // 生成唯一键值
    key = ftok(".", 123);
    if (key == -1) {
        perror("ftok");
        exit(EXIT_FAILURE);
    }

    // 创建或获取消息队列
    msqid = msgget(key, IPC_CREAT | 0666);
    if (msqid == -1) {
        perror("msgget");
        exit(EXIT_FAILURE);
    }
	printf("Message queue created with ID: %d\n", msqid);

    // 循环发送消息
    for (int i = 1; i <= 5; ++i) 
    {
        msg.msg_type = 1; // 消息类型为 1
        snprintf(msg.msg_text, sizeof(msg.msg_text), "Message %d from sender", i);

        if (msgsnd(msqid, &msg, strlen(msg.msg_text) + 1, 0) == -1) {
            perror("msgsnd");
            exit(EXIT_FAILURE);
        }
        printf("Sent: %s\n", msg.msg_text);
        sleep(1); // 模拟延时
    }
    return 0;
}

接收方

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

// 定义消息结构
struct msgbuf {
    long msg_type;       // 消息类型
    char msg_text[256];  // 消息内容
};

int main()
{
    key_t key;
    int msqid;
    struct msgbuf msg;

    // 生成唯一键值
    key = ftok(".", 123);
    if (key == -1) {
        perror("ftok");
        exit(EXIT_FAILURE);
    }

    // 获取消息队列
    msqid = msgget(key, 0666);
    if (msqid == -1) {
        perror("msgget");
        exit(EXIT_FAILURE);
    }
	printf("Message queue opened with ID: %d\n", msqid);
	
    // 循环接收消息
    while (1) 
    {
        if (msgrcv(msqid, &msg, sizeof(msg.msg_text), 1, 0) == -1) {
            perror("msgrcv");
            exit(EXIT_FAILURE);
        }
        printf("Received: %s\n", msg.msg_text);

        // 接收到特定内容时退出
        if (strcmp(msg.msg_text, "exit") == 0) {
            printf("Received exit signal. Exiting...\n");
            break;
        }
    }
    return 0;
}

输出

// 发送方
Message queue created with ID: 12345
Sent: Message 1 from sender
Sent: Message 2 from sender
Sent: Message 3 from sender
Sent: Message 4 from sender
Sent: Message 5 from sender

// 接收方
Message queue opened with ID: 12345
Received: Message 1 from sender
Received: Message 2 from sender
Received: Message 3 from sender
Received: Message 4 from sender
Received: Message 5 from sender
posted @   星竹z  阅读(25)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
点击右上角即可分享
微信分享提示