Linux消息队列实现跨进程通信的两个示例

在Linux内核中,System V消息队列和POSIX消息队列的实现原理是不同的。

System V消息队列是通过内核中的一个全局消息队列数组来实现的。每个消息队列都有一个唯一的标识符,可以通过该标识符在进程之间共享。进程可以使用系统调用msgget()来创建或获取一个消息队列,使用msgsnd()向消息队列中发送消息,使用msgrcv()从消息队列中接收消息,使用msgctl()来控制消息队列的属性。

POSIX消息队列是通过内核中的一个文件系统来实现的。每个消息队列都有一个唯一的名称,可以在文件系统中访问。进程可以使用系统调用mq_open()来创建或获取一个消息队列,使用mq_send()向消息队列中发送消息,使用mq_receive()从消息队列中接收消息,使用mq_unlink()来删除消息队列。

虽然System V消息队列和POSIX消息队列的实现原理不同,但它们都提供了类似的功能,可以用于进程之间的通信。

1、System V消息队列

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

#define MSG_SIZE 128

struct msgbuf {
    long mtype;
    char mtext[MSG_SIZE];
};

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

    // 创建消息队列
    key = ftok(".", 'a');
    msgid = msgget(key, 0666 | IPC_CREAT);
    if (msgid == -1) {
        perror("msgget");
        exit(1);
    }

    // 发送消息
    msg.mtype = 1;
    strcpy(msg.mtext, "Hello, world!");
    if (msgsnd(msgid, &msg, strlen(msg.mtext)+1, 0) == -1) {
        perror("msgsnd");
        exit(1);
    }

    // 接收消息
    if (msgrcv(msgid, &msg, MSG_SIZE, 0, 0) == -1) {
        perror("msgrcv");
        exit(1);
    }
    printf("Received message: %s\n", msg.mtext);

    // 删除消息队列
    if (msgctl(msgid, IPC_RMID, NULL) == -1) {
        perror("msgctl");
        exit(1);
    }

    return 0;
}

 这里面设计四个函数:msgget、msgsnd、msgrcv、msgctl,从函数名其实可以看出来它们的作用。

(1)msgget的用法和之前说过的shmget几乎一致,根据key去分配一个消息队列。

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgget(key_t key, int msgflg);

       The  msgget()  system call returns the System V message queue identifier associated with the value of the key argument.  A new message queue is created if key has the value IPC_PRIVATE or key isn't IPC_PRIVATE, no message queue with the given key key exists, and IPC_CREAT is specified in msgflg.

       If msgflg specifies both IPC_CREAT and IPC_EXCL and a message queue already exists for key, then msgget() fails with errno set to EEXIST.  (This is analogous  to  the effect of the combination O_CREAT | O_EXCL for open(2).)

(2)msgsnd和msgrcv是一套组合拳,

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

       The msgsnd() and msgrcv() system calls are used, respectively, to send messages to, and receive messages from, a System V message queue.  The calling process must have write permission on the message queue in order to send a message, and read permission to receive a message.

也因此,msgget的传入参数msgflg带上了0666。

另外关于IPC_NOWAIT这个flag,如果msgsnd和msgrcv没有指定的话,消息队列满了的话msgsnd会阻塞,消息队列空了的话msgrcv会阻塞。如果指定了该flag,那消息队列满了的话msgsnd会返回-1并将errno设置为EAGAIN,msgrcv会返回-1并将errno设置为E2BIG。

(3)msgctl通过不同的控制指令来实现相关功能,传入IPC_RMID则实现移除消息队列的功能。

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgctl(int msqid, int cmd, struct msqid_ds *buf);

2、POSIX消息队列

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <mqueue.h>
#include <string.h>

#define MAX_SIZE 1024
#define QUEUE_NAME "/my_queue"

int main() {
    mqd_t mq;
    struct mq_attr attr;
    char buffer[MAX_SIZE + 1];
    int msg_len, msg_prio;

    // 打开或创建消息队列
    mq = mq_open(QUEUE_NAME, O_CREAT | O_RDWR, 0666, NULL);
    if (mq == (mqd_t) -1) {
        perror("mq_open");
        exit(1);
    }

    // 发送消息
    if (mq_send(mq, "Hello, Message Queue!", strlen("Hello, Message Queue!"), 0) == -1) {
        perror("mq_send");
        exit(1);
    }

    printf("Message sent: Hello, Message Queue!\n");

    // 接收消息
    msg_len = mq_receive(mq, buffer, MAX_SIZE, &msg_prio);
    if (msg_len == -1) {
        perror("mq_receive");
        exit(1);
    }

    buffer[msg_len] = '\0';
    printf("Message received: %s\n", buffer);

    // 关闭消息队列
    if (mq_close(mq) == -1) {
        perror("mq_close");
        exit(1);
    }

    // 删除消息队列
    if (mq_unlink(QUEUE_NAME) == -1) {
        perror("mq_unlink");
        exit(1);
    }

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阅后即奋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值