进击吧,linux(十八) 消息队列通讯
0赞
Linux进程和进程之间有多种通讯方式。Linux进程间通讯的主要方式有:
1、 无名管道
2、 有名管道
3、 信号
4、 消息队列
5、 共享内存
6、 信号量
7、 套接字
消息队列就是一个消息的链表。而一条消息可以看作是一个记录,具有特定的格式。进程可以向消息队列中按照一定的规则添加新消息,另一个进程可以从消息队列中读取消息,这样通过消息对了,就实现了进程间的通讯。
同样,对于消息队列,也是有若干函数。
9.1.1 函数名
msgget
9.1.2 函数原型
int msgget(key_t key, int msgflg)
9.1.3 函数功能
打开或创建消息队列
9.1.4 函数所属头文件
<sys/types.h> <sys/ipc.h> <sys/msg.h>
9.1.5 函数返回值
成功: 消息对应标识符id
失败: -1
9.1.6 函数参数
key: 消息队列关联的键值
msgflg: 打开标志
-IPC_CREAT: 如果打开消息队列失败,则创建新的消息队列
9.2.1 函数名
msgsnd
9.2.2 函数原型
int msgsnd(int msqid, const void *msgp, size_t msgsz,int msgflg)
9.2.3 函数功能
往消息队列里面发送消息
9.2.4 函数所属头文件
<sys/types.h> <sys/ipc.h> <sys/msg.h>
9.2.5 函数返回值
成功:0
失败:-1
9.2.6 函数参数
msqid: 消息队列的标识符id
msgp: 指向要发送的消息指针
mtext的大小由msgzz决定
msgsz: 消息数据的大小
msgflg: 标志
9.3.1 函数名
msgrcv
9.3.2 函数原型
ssize_t msgrcv(int msgid, void *msgp, size_t msgsz, long msgtyp, int msgflg)
9.3.3 函数功能
从消息队列获取消息
9.3.4 函数所属头文件
<sys/types.h> <sys/ipc.h> <sys/msg.h>
9.3.5 函数返回值
成功:实际接收到的消息的数据量
失败:-1
9.3.6 函数参数
msgid:消息队列的id
msgp: 消息指针
msgsz: 希望取到消息的数据长度
msgtyp: 消息类型
-0: 消息队列的第一条消息取出
-大于0: 取消息队列中第一条类型等于msgtyp的消息
-小于0: 取消息队列中类型不超过msgtyp的绝对值中最小的消息
msgflg: 标志
9.4.1 函数名
msgctl
9.4.2 函数原型
int msgctl(int msgid, int cmd, struct msqid_ds *buf)
9.4.3 函数功能
消息队列的操作
9.4.4 函数所属头文件
<sys/types.h> <sys/ipc.h> <sys/msg.h>
9.4.5 函数返回值
成功:0
失败:-1
9.4.6 函数参数
msgid: 消息队列id
cmd: 命令
-IPC_STAT: 将内核数据复制到buf中
-IPC_SET: 设置buf参数,并该buf数据复制到内核数据中
-IPC_RMID: 删除消息队列
buf: 结构体指针
下面,就是写代码进行学习了。
有两个进程AB,进程A创建消息队列,并向消息队列中写数据,进程B从消息队列中读取数据。
#include<sys/types.h> #include<sys/ipc.h> #include<sys/msg.h> #include<stdio.h> #include<string.h> struct msgbuf{ long mtype; char mtext[1024]; }; void main() { key_t key; int msqid; char in[1024]; struct msgbuf msg; int msg_type; /*获取键值*/ key = ftok("/home",7); /*创建消息队列*/ msqid = msgget(key,IPC_CREAT); while(1) { printf("please input message type\n"); /*获取键盘输入*/ scanf("%d",&msg_type); printf("please input message content \n"); scanf("%s",in); msg.mtype = msg_type; strcpy(msg.mtext,in); /*发送到消息队列*/ msgsnd(msqid,&msg,sizeof(struct msgbuf),0); if(msg_type == 7777) break; } /*删除消息队列*/ msgctl(msqid,IPC_RMID,0); }
进程A中定义了一个结构体,这个结构体就是消息队列中规定的消息的结构体。第一个成员是消息类型,规定要大于0。第二个是消息内容数组,用来保存消息的数据。
首先是创建一个键值,然后创建消息队列和键值关联起来。然后就是一个无限循环,往消息队列中写入消息。如果一次消息发送的类型是7777,就退出循环,然后把消息队列删除。
进程B:
#include<sys/types.h> #include<sys/ipc.h> #include<sys/msg.h> #include<stdio.h> #include<string.h> struct msgbuf{ long mtype; char mtext[1024]; }; void main() { key_t key; int msqid; struct msgbuf msg; key = ftok("/home",7); /*打开消息队列*/ msqid = msgget(key, IPC_CREAT); while(1) { /*接收消息队列*/ msgrcv(msqid,&msg,sizeof(struct msgbuf),0,0); /*打印消息队列*/ printf("%d\n",msg.mtype); printf("%s\n",msg.mtext); if(msg.mtype == 7777) break; } }
进程B中也定义了一个和进程A中一样的结构体,功能是一样的。
先创建键值,并打开与键值关联的消息队列,这样就可以和A进程进行消息通信了。然后就不断读取消息队列中的数据,打印出来,如果消息队列中的数据的类型是7777,就退出循环。
这里接收消息用的是
msgrcv(msqid,&msg,sizeof(struct msgbuf),0,0);
第三个参数是0,表示接收消息队列的第一个数据。
程序运行:
B进程在等待读取消息数据,因为A进程还没有发送消息,所以就被阻塞了。
当A进程发送消息后,B进程就会收到该消息,然后将该消息打印出来。
当发送消息的类型是7777,AB进程就结束运行了。
将B进程的接收消息队列改为
msgrcv(msqid,&msg,sizeof(struct msgbuf),7,0);
表示只从消息队列中读取类型为7的消息。
运行程序的话,发送的消息类型不是7,就一直等待接收消息。
当发送消息类型为7,就接收消息。
将B进程的接收消息队列改为
msgrcv(msqid,&msg,sizeof(struct msgbuf),-7,0);
表示只从消息队列中读取类型为1——7的消息。
运行程序的话,发送消息类型为15,超过7,所以B进程等待接收消息。
当发送消息的类型不超过7后,B进程接收消息。
以上,就是消息队列通信了,消息队列通信,对于接收,有3种方式,一种是接收消息队列的第一个,一个是接收消息队列中指定的类型消息,最后一个是接收消息队列中的指定的范围类型的消息。