[Linux]-进程间通信之消息队列

目录

【消息队列的概述】

【消息队列的API】

1.获取系统唯一Key值(IPC键值)

2.创建消息队列

2.1查看消息队列的一些Linux命令

2.2消息队列的创建

3.消息的发送以及定义

3.1.通过消息队列发送信息

4.信息的接收

5.通过消息队列接受读取信息

6.消息队列的控制

【消息队列的总结】


【消息队列的概述】

之前我们使用过的管道比较适用于较少进程之间的通信,那么如果想要实现多个进程之前的通信的话,我们需要使用消息队列

消息队列具有如下特点

1.消息队列是消息的链表,存放于内存中,内核维护消息队列

2.消息队列中的消息是有类型的

3.消息队列中的消息是有格式的

4.消息队列可实现消息随机查询,并且不一定要遵循先进先出的顺序,而是每个进程可以按照感兴趣的类型进行读取

5.与管道相同,读出数据后,消息队列对应数据会被删除

6.每个管道都有消息队列标识符,在整个系统中是唯一的

7.消息队列允许一个或者多个进程向它写入或者读取数据

8.内核重启或者人为删除才会删除消息队列,否则会一直存在与系统中


【消息队列的API】

1.获取系统唯一Key值(IPC键值)

系统中可能会存在许多的消息队列,那么到底要怎么让进程区分到底是进入哪个消息队列呢,通过Key这个系统唯一值,可以选择想要进入的消息队列

这么理解,Key相当于假如聊天群聊的密码,如果你想要加入聊天,必须要有这个唯一的加入密码才可加入,不同的聊天群有不用的唯一密码(不同的消息队列有不用的密码)

其实这个Key值不仅是在消息队列中被使用,共享内存、信号等也使用

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

key_t ftok(const char *pathname, int proj_id);

功能

        获取项目相关唯一Key值

参数

        pathname:路径名

        proj_id:项目ID(非0整数)

返回值

        成功返回键值,失败-1

pathname这个参数可以随便设置的,因为Key值是通过所设置文件信息以及proj_id所合成Key值的,而proj_id这个数也是可以随便设置的。但是由于它只有8bit,也就是0-255.


2.创建消息队列

消息队列依赖于Key值创建,并且msgget函数并不仅仅是创建,如果消息队列已经存在,那么通过这个函数配合唯一键值就可以让不同的进程进入唯一的消息队列

#include <sys/msg.h>

int msgget(key_t key, int msgflg);

功能

        创建或者打开一个新的消息队列。即使进程不同,但是如果key值是相同的,那么也可以进入相同的消息队列,返回相同的消息队列标识符

参数

        key:IPC键值

        msgflg:表示函数的行为及消息队列的权限

        msgflag取值

                                IPC_CREAT:创建消息队列

                                IPC_EXCL:检测消息队列是否存在

                                位或权限位:消息队列位或权限位可以设置消息队列访问权限,和open函数的打开方式的mode_t一样

返回值

        成功:消息队列标识符

        失败:-1

2.1查看消息队列的一些Linux命令

ipcs -q                        

查看当前进程间通信之消息队列

解析

        ipc   就是进程间通信的意思

        s      search,搜索

        -q    消息队列的意思,还有很多可选项

ipcrm -q 队列号

删除指定的消息队列

解析

        ipc        进程间通信

        rm        删除,remove

        -q         消息队列


 下面是一些可选项(一般下面几个就是用到ipc键值的几种通信方式)

-m        共享内存

-q         消息队列

-s         信号量

-a         全部


2.2消息队列的创建

7e60d66f847d4738b1b43d80f3a2ea95.png

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int main(int argc, char const *argv[])
{

    //获取唯一键值
    key_t key = ftok("/",2023);
    printf("KEY为%#x\n",key);
    //通过key值生成消息队列
    int msg = msgget(key, IPC_CREAT | 0666 );
    printf("消息队列标识符为%d\n",msg);


    return 0;
}

3.消息的发送以及定义

消息队列中的信息是一个结构体,里面包含了消息类型以及消息正文两种类型,消息类型必须放在第一个,因为这个是每个进程读取消息的依据。消息正文可以有多个成员。

消息的结构体定义如下

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

#include <sys/msg.h>

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

功能

        将新消息添加到消息队列

参数

        msqid:消息队列标识符

        msgp:待发送消息结构体地址

        msgsz:消息正文字数(结构体大小减去结构体中成员大小)

        msgflg:函数的控制属性

                      0:msgsnd调用阻塞直到满足条件为止

                      IPC_NOWAIT:若消息没有立即发送,调用该函数的进程会立即返回

返回值

        成功 0

        失败 -1  

        

3.1.通过消息队列发送信息

a869e8e8149b4b6fb92a54198bbd4544.png

int main(int argc, char const *argv[])
{

    //获取唯一键值
    key_t key = ftok("/",2023);
    printf("KEY为%#x\n",key);
    //通过key值生成消息队列
    int msg = msgget(key, IPC_CREAT | 0666 );
    printf("消息队列标识符为%d\n",msg);


    //编辑消息队列信息
    MSG _msg;
    memset(&msg,0,sizeof(msg));
    //不同进程通过消息队列获取信息的一依据
    _msg.mstype = 20;
    strcpy(_msg.mstext,"bob:hello msg");

    //发送消息
    msgsnd(msg,&_msg,sizeof(_msg)-sizeof(long),0);

    return 0;
}

4.信息的接收

#include <sys/msg.h>

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

功能

        从指定的消息队列标识符中接受信息,同时一旦接受成功,从消息队列中删除该信息。

参数

        msqid:消息队列标识符

        msgp:存放信息的结构体地址

        msgsz:消息正文的字节数

        msgtyp:感兴趣的消息类型(不同进程从消息队列中接受感兴趣数据的依据)

                        =0:接受队列第一个信息

                        >0:接受等于msgtyp的信息

                        <0:返回队列中消息类型值小于或者等于msgtyp的绝对值的值,若有多个,则取最小的值

        msgtyp注意事项

                        如果消息队列中有多个类型的信息,那么获取信息就是按照消息类型获取,而不是按照先进先出的情况下获取

                        如果某个消息类型是一样的并且有多条,那么按照先进先出的情况获取

        

        msgflg:

                        0:阻塞直到接收到信息为止

                        MSG_NOERROR:MSG NOERROR:若返回的消息字节数比nbytes字节数多,则消息就会截短到nbytes字节,且不通知消息发送进程

                        IPC_NOWAIT:调用进程会立即返回。若没有收到消息则立即返回-1

返回值

        成功:读取到字节个数

        失败:-1


5.通过消息队列接受读取信息

假设msgtyp的值为20,那么从消息队列读取数据的进程按照msgtyp为20作为感兴趣的值来读取数据。

43139b2f7c6c4464a92338cac6d0344b.png

发送信息方

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
typedef struct _msg
{
    long mstype;
    char mstext[128];
}MSG;



int main(int argc, char const *argv[])
{

    //获取唯一键值
    key_t key = ftok("/",2023);
    printf("KEY为%#x\n",key);
    //通过key值生成消息队列
    int msg = msgget(key, IPC_CREAT | 0666 );
    printf("消息队列标识符为%d\n",msg);


    //编辑消息队列信息
    MSG _msg;
    memset(&msg,0,sizeof(msg));
    //不同进程通过消息队列获取信息的一依据
    _msg.mstype = 20;
    strcpy(_msg.mstext,"bob:hello msg");

    //发送消息
    msgsnd(msg,&_msg,sizeof(_msg)-sizeof(long),0);
    printf("消息发送成功!\n");
    return 0;
}

接受信息方

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
typedef struct _msg
{
    long mstype;
    char mstext[128];
}MSG;

int main(int argc, char const *argv[])
{
    //获取唯一键值
    key_t key = ftok("/",2023);
    printf("KEY为%#x\n",key);
    //通过key值生成消息队列
    int msg = msgget(key, IPC_CREAT | 0666 );
    printf("消息队列标识符为%d\n",msg);


    //编辑消息队列信息
    MSG _msg;
    memset(&msg,0,sizeof(msg));

    //接受消息
    printf("lucy准备接受消息...\n");
    msgrcv(msg, &_msg, sizeof(_msg)-sizeof(long), 20,0);
    printf("接收到消息%s\n",_msg.mstext);





    return 0;
}

6.消息队列的控制

#include <sys/msg.h>

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

功能

        对消息队列进行修改,修改属性或者删除消息队列等

参数

        msqid:消息队列标识符

        cmd:函数功能控制

        buf:msqid_ds数据类型地址,用来存放或者更改消息队列属性

        cmd

                IPC_RMID:删除该消息队列标识符的队列,从系统删除并破坏相关结构

                IPC_STAT:将该消息队列标识符表示的的消息队列各个元素值存到buf结构体中

                IPC_SET:将buf结构体中的数据设置到消息队列中

返回值

        成功 0

        失败 -1


【消息队列的总结】

如果一个进程想要访问或者创建一个消息队列,那么应该使用ftok获取一个唯一键值,然后通过这个IPC键值来访或者创建消息队列(多个进程通信就像是创建聊天群,进入聊天群的密码就是IPC键值,密码唯一)。只有成功进入消息队列才可以收发信息。

当进入消息队列,发送信息只能通过消息结构体struct msgbuf来接受,并且第一个成员一定要是mtype,因为这决定了进程从消息队列读取信息的依据,只读取感兴趣的类型(mtype)的数据。

管道比较适合进程比较少的通信,消息队列比较适合进程比较多的通信

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Leviiil

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

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

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

打赏作者

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

抵扣说明:

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

余额充值