消息队列
这一节,我们讲进程通信的又一种方式,消息队列。
什么是消息队列?
消息队列是消息的链表,存放在内核中并由消息队列标识符表示。
消息队列提供了一个从一个进程向另一个进程发送数据块的方法,每个数据块都可以被认为是有一个类型,接受者接受的数据块可以有不同的类型。
简单用一张图理解:
可以看到,在两个进程之间,可以用之前讲过的两种管道方式通信:一种亲缘关系进程,一种不是亲缘关系进程。
而消息队列由内核管理,就像一个一的链表一样,有自己的id号,通过key键值索引找到,进程A插入一个新的节点,将传入的消息写入进去插入后,B进程访问这个队列从而读出消息。(可以这样简单理解,可能说的不专业,但应该更好理解把。)
还要来看一看和键值key相关的ftok函数。
系统建立IPC通讯(如消息队列、共享内存时)必须指定一个ID值。通常情况下,该id值通过ftok函数得到。
ftok原型如下:
key_t ftok( char * fname, int id )
fname就时你指定的文件名(该文件必须是存在而且可以访问的),id是子序号,虽然为int,但是只有8个比特被使用(0-255)。
当成功执行的时候,一个key_t值将会被返回,否则 -1 被返回。
简单来说,ftok创建一个key值,也可以是创建一个通讯的索引,这个索引可以作为消息队列的队列。
然后,来看看几个要用到的api,
1.msgget 创建队列
int msgget(key_t key,int flag);
key:索引值
flag:打开队列的方式,一般为IPC_CREAT
int型为队列的ID
成功返回队列ID,失败返回-1
2.msgsnd 发送消息
int msgsnd(int msgid(队列id),指针类型(消息),消息的大小,falg(标志位))
成功返回队列ID,失败返回-1
3.msgrcv 读取消息
int msgrcv(int msgid(队列id),消息的大小,type消息的类型,falg(标志位))
4.msgctl对消息队列进行操作
int msgctl(int msgid(队列id),int cmd,buf);
好,我们仍然是用两个进程来测试:
send.c发送消息的进程
get.c接收消息的进程
# 思路讲解:
首先,在get进程中,
1.写一个消息队列的结构体,(这个样式是Linux提供的样板,可以就这样用),
2.创建一个用来插入消息队列的结点(结构体)。
3.索引一个消息队列,键值通过ftok函数获得,通过msgrcv函数获取这个消息队列的内容。
4.在内核中除去这个队列,以免过多消息队列出现。
在send进程中
1.写一个消息队列的结构体,(这个样式是Linux提供的样板,可以就这样用),
2.创建一个用来插入消息队列的结点(结构体)。
3.索引一个消息队列,键值通过ftok函数获得,通过msgrcv函数获取这个消息队列的内容。
4.实例化一个结构体,把要写入的信息写进去结构体的成员mtext中去,把这个结构体写入消息队列。
运行get后,消息队列中没有能够读取到的东西,会堵塞,直到send内容后才能读取到东西。
来看看运行结果:
运行结果:
可以看到,get从消息队列中读取到了写入的话,实现了进程间的通信。
(师上官可编程)