Linux进程通信之消息队列

2024-01-09 17:33:50

目录

1、消息队列介绍

2、消息队列的特点

?3、消息队列涉及的函数

1.msgflg参数的两个主要标志位:

2.函数msgrcv在读取消息队列时,type参数有下面几种情况:

3.函数msgctl对消息队列进行操作时cmd常用的操作命令有

4、ftok函数的单独介绍

5、示例


1、消息队列介绍

消息队列(Message Queue)是一种在进程间进行通信的机制,是消息的链接表,允许一个进程向另一个进程发送数据。消息队列是通过在内核中创建的一个消息缓冲区来实现的,允许多个进程向同一队列发送消息,并从中读取消息。

2、消息队列的特点

  1. 消息队列中的消息通常是一个结构体,包含一个消息类型标识符和实际的消息数据。接收进程可以选择接收特定类型的消息。
  2. 每个消息队列都有一个唯一的标识符,用于标识消息队列。进程通过这个标识符访问消息队列。
  3. 消息队列是独立于发送和接收进程,进程终止时消息队列机器内容并不会被删除,由Linux内核来决定消息队列及其内容什么时候被删除。
  4. 消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取。

?3、消息队列涉及的函数

?// 创建或打开消息队列:成功返回队列ID,失败返回-1
1 int msgget(key_t key, int msgflg);
?// 写入消息:成功返回0,失败返回-1
2 int msgsnd(int msqid, const void *ptr, size_t size, int msgflg);
?// 读取消息:成功返回接收到的消息的字节数,失败返回-1
3 int msgrcv(int msqid, void *ptr, size_t size, long type,int msgflg);
?// 控制消息队列:成功返回0,失败返回-1
?4 int msgctl(int msqid, int cmd, struct msqid_ds *buf);

1.msgflg参数的两个主要标志位:

  1. IPC_CREAT: 如果消息队列不存在,则创建一个新的消息队列。
  2. IPC_EXCL:IPC_CREAT 一同使用时,如果消息队列已经存在,则返回错误。如果未指定 IPC_EXCL,即使消息队列已经存在,也会返回其标识符。?

当创建一个新的消息队列时,我们需要在标志位IPC_CREAT的后面或(|)上消息队列的访问权限,表示当key命名的消息队列不存在时创建一个消息队列,当key所命名的消息队列存在时则被忽略。

2.函数msgrcv在读取消息队列时,type参数有下面几种情况:

  • type == 0,返回队列中的第一个消息;
  • type > 0,返回队列中消息类型为 type 的第一个消息;
  • type < 0,返回队列中消息类型值小于或等于 type 绝对值的消息,如果有多个,则取类型值最小的消息。

可以看出,type值非 0 时用于以非先进先出次序读消息。也可以把 type 看做优先级的权值

3.函数msgctl对消息队列进行操作时cmd常用的操作命令有

  • IPC_STAT: 获取消息队列的状态信息,将其存储在 buf 中。
  • IPC_SET: 设置消息队列的状态信息,使用 buf 中提供的值。
  • IPC_RMID: 删除消息队列。

而参数buf:指向 struct msqid_ds 结构体的指针,用于传递或接收消息队列的状态信息,当我们使用的是IPC_RMID时这里可以设置为空。

4、ftok函数的单独介绍

ftok 函数用于生成一个与文件路径名和项目 ID 相关的键值

函数原型:key_t ftok(const char *pathname, int proj_id);

参数介绍:

  • pathname:文件路径名,可以是一个现有的文件。通常选择一个存在的文件,因为 ftok 使用文件的 inode 号和 proj_id 来生成键值。
  • proj_id:项目 ID,为整数。

ftok 函数通过将文件的 inode 号和项目 ID 整合在一起,产生一个唯一的键值。这个键值在 IPC 对象(例如消息队列、信号量、共享内存)的创建和访问中用于标识对象。

5、示例

发送并接收

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

// 定义消息结构体
struct msgbuf {
    long mtype;       // 消息类型,必须大于 0
    char mtext[128];  // 消息数据
    int index;        // 额外的索引信息
};

int main() {
    // 通过 ftok 创建键值
    key_t key = ftok(".", 5);
    printf("key = %x\n", key);

    // 创建或获取消息队列
    int msqid = msgget(key, 0777 | IPC_CREAT);
    if (msqid == -1) {
        printf("msgget 失败!!!\n");
        perror("why");
    } else {
        // 发送消息
        struct msgbuf sendbuf = {88, "happy bay!!!", 88};
        msgsnd(msqid, &sendbuf, strlen(sendbuf.mtext) + sizeof(sendbuf.index), 0);

        // 接收消息
        struct msgbuf rcvbuf;
        msgrcv(msqid, &rcvbuf, sizeof(rcvbuf.mtext) + sizeof(rcvbuf.index), 100, 0);
        printf("read: %s, index: %d\n", rcvbuf.mtext, rcvbuf.index);
    }

    // 删除消息队列
    msgctl(key, IPC_RMID, NULL);

    return 0;
}

接收并发送

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

// 定义消息结构体
struct msgbuf {
    long mtype;       // 消息类型,必须大于 0
    char mtext[128];  // 消息数据
    int index;        // 额外的索引信息
};

int main() {
    // 通过 ftok 创建键值
    key_t key = ftok(".", 5);
    printf("key = %x\n", key);

    // 创建或获取消息队列
    int msqid = msgget(key, 0777 | IPC_CREAT);
    if (msqid == -1) {
        printf("msgget 失败!!!\n");
        perror("why");
    } else {
        // 接收消息
        struct msgbuf rcvbuf;
        msgrcv(msqid, &rcvbuf, sizeof(rcvbuf.mtext) + sizeof(rcvbuf.index), 88, 0);
        printf("read: %s, index = %d\n", rcvbuf.mtext, rcvbuf.index);

        // 发送消息
        struct msgbuf sendbuf = {100, "thank you wjh !!!", 100};
        msgsnd(msqid, &sendbuf, strlen(sendbuf.mtext) + sizeof(sendbuf.index), 0);
    }

    // 删除消息队列
    msgctl(key, IPC_RMID, NULL);

    return 0;
}

文章来源:https://blog.csdn.net/weixin_58198422/article/details/135439818
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。