消息队列Linux

 1. 概念

  • 消息队列是由消息组成的链表,存放于内存中,由内核维护。
  • 每个消息可定义为一个结构体,存放消息类型、消息正文等数据。
  • 只有内核重启或用户删除才会删除消息队列。
  • 每个消息队列的标识符(ID)都是唯一的,类似共享内存的ID。

定义消息结构体:

typedef struct msgbuf
{
	long 	mtype;        //消息类型,必须放在第一个
	char	mtext[128];   //消息正文,可有多个
    //.....
} MSG;

消息队列相关的Linux命令:

  • 查看消息队列:ipcs -q
  • 删除指定的消息队列:ipcrm -q 队列号

其它选项:①-m:共享内存;②-q:消息队列;③-s:信号量;④-a:全部。

2. 创建消息队列

调用msgget函数:

【1】头文件:#include <sys/types.h>、#include <sys/ipc.h>、#include <sys/msg.h>

【2】函数原型:int msgget(key_t key, int msgflg);

【3】参数说明:

  • key:是IPC键值,可以通过ftok函数来创建(与共享内存类似)
  • msgflg:创建消息队列指定的属性。
    • IPC_CREAT:创建消息队列,需要或上消息队列的权限
    • IPC_EXCL:检测消息队列是否存在,若存在函数返回-1

【4】返回值:成功返回消息队列ID,失败返回-1.

程序实例:创建消息队列并查看其信息。

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

int main(int argc, char **argv)
{
    //创建key
    key_t key = ftok("./", 222);
    printf("key = %#x\n", key);

    //创建消息队列
    int id = msgget(key, IPC_CREAT | 0664);
    if (id < 0) {
        perror("msgget error");
        return -1;
    }
    printf("msgQueue ID: %d\n", id);
    return 0;
}

3. 添加新消息到消息队列

调用msgsnd函数:

【1】头文件:#include <sys/types.h>、#include <sys/ipc.h>、#include <sys/msg.h>

【2】函数原型:int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

【3】参数说明:

  • msqid:消息队列的id
  • msgp:待发送消息结构体地址
  • msgsz:消息正文字数(结构体大小减去结构体中成员大小)
  • msgflg:函数的控制属性
    • 0:msgsnd调用阻塞直到满足条件为止
    • IPC_NOWAIT:若消息没有立即发送,调用该函数的进程会立即返回

【4】返回值:成功返回0,失败返回-1.

程序实例:创建消息队列,并添加一个新消息,其中新消息正文为"Hello, Can!"

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

typedef struct msgbuf
{
    long mtype;
    char mtext[128];
} MSG;

int main(int argc, char **argv)
{
    //创建key
    key_t key = ftok("./", 222);
    printf("key = %#x\n", key);

    //创建消息队列
    int id = msgget(key, IPC_CREAT | 0664);
    if (id < 0) {
        perror("msgget error");
        return -1;
    }
    printf("msgQueue ID: %d\n", id);

    //添加新消息到消息队列
    MSG msg;
    memset(&msg, 0, sizeof(msg));
    msg.mtype = 20;
    strcpy(msg.mtext, "Hello, Can!");
    msgsnd(id, &msg, sizeof(msg) - sizeof(long), 0);
    return 0;
}

4. 获取消息队列中的消息

调用msgrcv函数:从指定ID的消息队列中接收信息,一旦接受成功,从消息队列中删除该信息。

【1】头文件:#include <sys/types.h>、#include <sys/ipc.h>、#include <sys/msg.h>

【2】函数原型:ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

【3】参数说明:

  • msqid:消息队列的id
  • msgp:保存消息信息的结构体地址
  • msgsz:消息正文字节数
  • msgtyp:
    • 0:接收消息队列中的第一个消息。
    • >0:接收等于msgtyp的信息。
    • <0:返回队列中消息类型值小于或者等于msgtyp的绝对值的值,若有多个则取最小值。
  • msgflg:函数的控制属性
    • 0:阻塞直到满足条件为止
    • MSG NOERROR:若返回的消息字节数比nbytes字节数多,则消息就会截短到nbytes字节,且不通知消息发送进程
    • IPC_NOWAIT:若消息没有立即发送,调用该函数的进程会立即返回

【4】返回值:成功返回读取的字节数,失败返回-1.

5. 删除消息队列

调用msgctl函数:

【1】头文件:#include <sys/types.h>、#include <sys/ipc.h>、#include <sys/msg.h>

【2】函数原型:int msgctl(int msqid, int cmd, struct msqid_ds *buf);

【3】参数说明:

  • msqid:消息队列的id
  • cmd:控制命令参数
    • IPC_RMID:删除该消息队列标识符的队列,从系统删除并破坏相关结构。
    • IPC_STAT:将该消息队列标识符表示的的消息队列各个元素值存到buf结构体中。
    • IPC_SET:将buf结构体中的数据设置到消息队列中
  • buf:msqid_ds数据类型地址,用来存放或者更改消息队列属性。

【4】返回值:成功返回0,失败返回-1.

【5】删除示例:msgctl(id, IPC_RMID, NULL);

综合实例:写两个程序,一个程序作为发送消息方,一个程序作为接收消息方。发送消息方往消息队列中添加消息,接收消息方从消息队列中获取对应的消息。

发送消息方:

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

typedef struct msgbuf
{
    long mtype;
    char mtext[128];
} MSG;

int main(int argc, char **argv)
{
    //创建key
    key_t key = ftok("./", 222);
    printf("发送方: key = %#x\n", key);

    //创建消息队列
    int id = msgget(key, IPC_CREAT | 0664);
    if (id < 0) {
        perror("msgget error");
        return -1;
    }
    printf("发送方: msgQueue ID: %d\n", id);

    //添加新消息到消息队列
    MSG msg;
    memset(&msg, 0, sizeof(msg));
    msg.mtype = 20;
    strcpy(msg.mtext, "Hello, Can!");
    msgsnd(id, &msg, sizeof(msg) - sizeof(long), 0);
    printf("发送方: 消息内容 = %s\n", msg.mtext);
    return 0;
}

接收消息方:

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

typedef struct msgbuf
{
    long mtype;
    char mtext[128];
} MSG;

int main(int argc, char **argv)
{
    //创建key
    key_t key = ftok("./", 222);
    printf("接收方: key = %#x\n", key);

    //创建消息队列
    int id = msgget(key, IPC_CREAT | 0664);
    if (id < 0) {
        perror("msgget error");
        return -1;
    }
    printf("接收方: msgQueue ID: %d\n", id);

    //从消息队列中获取消息
    MSG msg;
    msgrcv(id, &msg, sizeof(msg) - sizeof(long), 20, 0);
    printf("接收方: 消息内容 = %s\n", msg.mtext);
    return 0;
}

相关推荐

  1. Linux消息队列

    2024-07-14 00:02:01       43 阅读
  2. Linux进程间通信之消息队列

    2024-07-14 00:02:01       43 阅读
  3. Linux】System V 消息队列(不重要)

    2024-07-14 00:02:01       28 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-14 00:02:01       66 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-14 00:02:01       70 阅读
  3. 在Django里面运行非项目文件

    2024-07-14 00:02:01       57 阅读
  4. Python语言-面向对象

    2024-07-14 00:02:01       68 阅读

热门阅读

  1. 商汤:带来实时的流式多模态AI交互体验

    2024-07-14 00:02:01       21 阅读
  2. hnust 1803: 二叉树遍历1

    2024-07-14 00:02:01       24 阅读
  3. python的seek()和tell()

    2024-07-14 00:02:01       23 阅读
  4. 关于浏览器Devtools的open,close监听

    2024-07-14 00:02:01       14 阅读
  5. 实时流媒体传输开源库Live555

    2024-07-14 00:02:01       20 阅读