消息队列:消息队列就是消息的一个链表,可以把消息看做一个记录,具有特定的格式。进程可以按照规定的格式向消息队列中添加新信息,而另一些进程可以从消息队列中读取消息。
在进程间通讯的方式中信号可以发送的信号有限,而管道也只能发送无格式的字节流,这对于我们开发应用程序会产生不便,而消息队列则克服了这些缺点。
分类:目前主要有两种类型的消息队列:POSIX消息队列以及系统V消息队列,系统V消息队列目前被大量使用。
POSIX指的是可移植的操作系统接口。
持续性:系统V消息队列是随内核持续的,只有在内核重启或者人工删除时,该消息队列才会被删除。
键值:消息队列的内核持续性要求每个消息队列都在系统范围内对应唯一的键值,所以,要获得一个消息队列的描述字,必须提供该消息队列的键值。
系统V消息队列的使用
获取键值的函数:
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(char *pathname, char proj)
返回值为文件名对应的键值。
pathname: 文件名
proj: 项目名(不为0即可)
ftok函数名是file to key的缩写
打开/创建函数
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg)
key:键值,由ftok获得。
msgflg:标志位。
返回值与键值相对应的消息队列描述字。
标志位的类型:
IPC_CREAT 创建新的消息队列
IPC_EXCL 与IPC_CREAT一同使用,表示如果要创建的消息队列已经存在,则返回错误
IPC_NOWAIT 读写消息队列请求无法被满足时,不阻塞。
在以下两种情况下,将创建一个新的消息队列:
1、如果没有与键值KEY相对应的消息队列,并且msgflg中包含了IPC_CREAT标志位。
2、KEY参数为IPC_PRIVATE。
发送消息的函数
#include <sys/types.h>
#include <sys/ipc.h>
#Include <sys/msg.h>
int msgsnd(int msqid,struct msgbuf *msgp, int msgsz, int msgflg)
参数意义
msqid 已打开的消息队列ID
msgp 存放消息的结构
msgsz 消息数据长度
msgflg 发送标志,有意义的msgflg标志为IPC_NOWAIT,指明在消息队列没有足够空间容纳要发送的消息时,msgsnd是否等待
消息格式
struct msgbuf {
long mtype; //消息类型>0
char mtex[1]; //消息数据的首地址
};
接收消息的函数
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgrcv(int msqid,struct msgbuf *msgp, int msgsz,long mtype, int msgflg)
除了第四个参数以外,其他的参数和发送消息的函数的参数是一样的。
功能:从msqid代表的消息队列中读出一个类型为mtype的数据。
注意:当函数成功从消息队列中读出一条消息后,消息队列中的这条消息将删除。
同进程中使用消息队列
1 #include <sys/types.h>
2 #include <sys/ipc.h>
3 #include <sys/msg.h>
4 #include <stdio.h>
5 #include <sys/stat.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <string.h>
9 #define FIFE "/home/book/c/msg_test"
10
11 struct msg_buf { //构造消息格式
12 long mtype;
13 char data[256];
14 };
15
16 int main(int argc, char **argv)
17 {
18 key_t key;
19 int msgid;
20 int ret;
21 struct msg_buf msgbuf;
22
23 key = ftok(FIFE,10);
24
25 msgid = msgget(key,IPC_CREAT | 0666);
26 if (msgid == -1) {
27 printf("can not create quenue\n");
28 exit(1);
29 }
30 msgbuf.mtype = 3;
31 strcpy(msgbuf.data,"msg test word"); //将数据放入结构体中
32 ret = msgsnd(msgid,&msgbuf,sizeof(msgbuf.data),IPC_NOWAIT);
33 if (ret == -1) {
34 printf("can not send\n");
35 exit(1);
36 }
37 memset(&msgbuf,0,sizeof(msgbuf));
38 ret = msgrcv(msgid,&msgbuf,sizeof(msgbuf.data),msgbuf.mtype,IPC_NOWAIT);
39 if (ret == -1) {
40 printf("can not receive\n");
41 exit(1);
42 }
43 printf("msg is %s\n",msgbuf.data);
44
45 exit(0);
46 }
运行结果
消息队列应用于不同的进程
发送消息的进程send.c
1 #include <sys/types.h>
2 #include <sys/ipc.h>
3 #include <sys/msg.h>
4 #include <stdio.h>
5 #include <sys/stat.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <string.h>
9 #define FIFE "/home/book/c/msg_test"
10
11 struct msg_buf {
12 long mtype;
13 char data[256];
14 };
15
16 int main(int argc, char **argv)
17 {
18 key_t key;
19 int msgid;
20 int ret;
21 struct msg_buf msgbuf;
22
23 key = ftok(FIFE,10);
24
25 msgid = msgget(key,IPC_CREAT | 0666);
26 if (msgid == -1) {
27 printf("can not create quenue\n");
28 exit(1);
29 }
30 msgbuf.mtype = 111; //设置消息类型
31 strcpy(msgbuf.data,"msg test word");
32 ret = msgsnd(msgid,&msgbuf,sizeof(msgbuf.data),IPC_NOWAIT);
33 if (ret == -1) {
34 printf("can not send\n");
35 exit(1);
36 }
37 else {
38 printf("send1 success\n");
39 }
40 memset(&msgbuf,0,sizeof(msgbuf));
41 msgbuf.mtype = 222;
42 strcpy(msgbuf.data,"msg test2222 word");
43 ret = msgsnd(msgid,&msgbuf,sizeof(msgbuf.data),IPC_NOWAIT);
44 if (ret == -1) {
45 printf("can not send\n");
46 exit(1);
47 }
48 else {
49 printf("send2 success\n");
50 }
51
52 exit(0);
53 }
运行效果
这时数据已经发送到消息队列中了。
接受函数receive.c
1 #include <sys/types.h>
2 #include <sys/ipc.h>
3 #include <sys/msg.h>
4 #include <stdio.h>
5 #include <sys/stat.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <string.h>
9 #define FIFE "/home/book/c/msg_test"
10
11 struct msg_buf {
12 long mtype;
13 char data[256];
14 };
15
16 int main(int argc, char **argv)
17 {
18 key_t key;
19 int msgid;
20 int ret;
21 struct msg_buf msgbuf;
22
23 key = ftok(FIFE,10);
24
25 msgid = msgget(key,0);
26 if (msgid == -1) {
27 printf("can not create quenue\n");
28 exit(1);
29 }
30 msgbuf.mtype = (long)argv[1]; //根据输入的类型确定要读取的消息
31 memset(&msgbuf,0,sizeof(msgbuf));
32 ret = msgrcv(msgid,&msgbuf,sizeof(msgbuf.data),msgbuf.mtype,IPC_NOWAIT);
33 if (ret == -1) {
34 printf("can not receive\n");
35 exit(1);
36 }
37 printf("msg is %s\n",msgbuf.data);
38
39 exit(0);
40 }
运行效果