进程通讯(四)--消息队列
消息队列和管道很像。但它比起管道不需要固定进程的只读和只写,通讯间的进程都可以读写,并且支持多个进程。




而消息队列发送的消息 实际是一个消息类型和实际的消息。消息类型是什么?它其实是一个长整型数字,具体多少完全由用户来定义,为的是读消息时可以根据这个类型来调整读取的优先级顺序。
所以说消息队列发送的是数据块,一般发送的消息就定义为以下的结构体。
struct msg
{
long type;//自定义的消息类型
char buff[N] ; //实际的数据比如字符数组形势的
}
消息队列的具体使用
这里要四个函数
1.int msgget(key_t key,int msgflg);
和信号量差不多的获取函数,不过比起信号量获取后还要semctl初始值来说,第一次获取消息队列在此函数第二个参数加|IPC_CREAT 就直接创建新的队列,不用进行初始化。key值仍为用户随意定义的值,第二个就是权限 加 IPC_CREAT等宏(可选),返回值-1表示失败,成功返回标识符msgid。
2.int msgsnd(int msgid,const void *msg_ptr,size_t msg_sz,int msgflag)
第一个参数为msgget函数标返回的识符,无需多说。
第二个就是我们要发送的消息的指针,就是上面定义的那个 消息类型+实际消息 的结构体指针。
第三个参数就是发送的实际消息的长度,即从第二个参数指针后跳过一个long类型长度开始取内容。
第四个参数是一些宏,控制消息队列满了或者超过系统范围的一些情况,目前我们基础的都写0就好。
3.int msgrcv(int msgid,void *msg_ptr,size_t msg_sz,long int type,int msgflg);
前三个参数和msgsnd的前三个差不多,不过值得注意的是这里的第二个参数是要接收消息的指针,即自己定义的接受消息缓冲区结构体的指针。
第四个参数就比较有意思了,也算是消息队列的核心用法吧,这里接收的消息就会按第四个参数里long型type值去接受,即假如消息队列里有一个1234类型的消息在中间,我要是第四个参数就写1234,那么就会优先接收到那个1234类型的消息,不像管道一样,必须先接收队头的消息。还有几个用法就是,如果写成0,那么就会·按着消息队列的顺序读消息。如果写成-n,那么只会读类型小于等于n的消息
第五个参数也是一些宏,处理消息队列中没有第四个参数的值的类型的情况。一般我们也取0吧。
最后返回值-1表示失败,成功返回第二个参数接受到的字节数。
4.int msgctl(int msgid ,int command,struct msgid_ds buf);
和其他方式IPC的控制函数一样,第二个参数三个值
IPC_STAT, IPC_SET, IPC_RMID
当第二个参数为IPC_RMID,表示要删除消息队列,可以无视第三个参数,设为0就好。
至于IPC_STAT, IPC_SET
前者是第三个参数的结构体设为当前的消息队列关联值。
后者是把消息队列的关联值设为第三个参数结构体里的值。
第三个参数的结构体就是一些用户 组 ,访问权限之类的东西。
最后还是用一道题来示范下用法吧。
题目如下,A进程负责输入类型和数据,BC进程分别负责读取类型为1000和2000的数据。
其实BC可以写成一份代码,在main函数传参分情况讨论就好
A进程代码:
BC进程代码:
结果如下: