1,首先,我们应该说清楚什么是消息队列?(以下为网络资料)
消息队列提供了一种从一个进程向另一个进程发送一个数据块的⽅方法。 每个数据块都被认
为是有一个类型,接收者进程接收的数据块可以有不同的类型值。
可以这么说消息队列就是一个消息的链表。每个消息队列都有一个队列头,用结构struct msg_queue来描述。队列头中包含了该消息队列的大量信息,包括消息队列键值、用户ID、组ID、消息队列中消息数目等等。
2,这是消息队列的结构
第一行为IPC对象数据结构。
3,如何创建消息队列并且使用它?我们需要用到一些函数。
原型:int msgget(key_t key, int msgflg);
参数:
key:可以认为是⼀一个端⼜⼝口号,也可以由函数ftok⽣生成。
msgflg:
IPC_CREAT 如果IPC不存在,则创建⼀一个IPC资源,否则打开操作。
IPC_EXCL:只有在共享内存不存在的时候,新的共享内存才建⽴立,否则就产⽣生错误。
如果单独使⽤用IPC_CREAT,XXXget()函数要么返回⼀一个已经存在的共享内存的操作符,要
么返回⼀一个新建的共享内存的标识符。
如果将IPC_CREAT和IPC_EXCL标志⼀一起使⽤用,XXXget()将返回⼀一个新建的IPC标识符
;如果该IPC资源已存在,或者返回-1。
IPC_EXEL标志本⾝身并没有太⼤大的意义,但是和IPC_CREAT标志⼀一起使⽤用可以⽤用来保证
所得的对象是新建的,⽽而不是打开已有的对象。
2.向队列读/写消息
原型:
**msgrcv从队列中取⽤用消息:ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int
msgflg);**
msgsnd将数据放到消息队列中:int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
参数:
msqid:消息队列的标识码
msgp:指向消息缓冲区的指针,此位置⽤用来暂时存储发送和接收的消息,是一个⽤用户可
定义的通⽤用结构,形态如下:
struct msgstru{
long mtype; //大于0
}
msgsz:消息的⼤大⼩小。
msgtyp:从消息队列内读取的消息形态。如果值为零,则表⽰示消息队列中的所有消息都
会被读取。
msgflg:⽤用来指明核⼼心程序在队列没有数据的情况下所应采取的⾏行动。如果msgflg和常
数IPC_NOWAIT合⽤用,则在msgsnd()执⾏行时若是消息队列已满,则msgsnd()将不会阻塞,⽽而
会⽴立即返回-1,如果执⾏行的是msgrcv(),则在消息队列呈空时,不做等待马上返回-1,并设定
错误码为ENOMSG。当msgflg为0时,msgsnd()及msgrcv()在队列呈满或呈空的情形时,采取
阻塞等待的处理模式。
3.设置消息队列属性
原型:int msgctl ( int msgqid, int cmd, struct msqid_ds *buf );
参数:msgctl 系统调⽤用对 msgqid 标识的消息队列执⾏行 cmd 操作,系统定义了 3 种 cmd 操作
: IPC_STAT , IPC_SET , IPC_RMID
IPC_STAT : 该命令⽤用来获取消息队列对应的 msqid_ds 数据结构,并将其保存到 buf 指
定的地址空间。
IPC_SET : 该命令⽤用来设置消息队列的属性,要设置的属性存储在buf中。
IPC_RMID : 从内核中删除 msqid 标识的消息队列。
简单示例:
我们创建2个进程,进程A创建消息队列并发送消息,给进程B,之后进程B给进程A发消息。
代码如下:
head.h:
#ifndef _HEAD_
#define _HEAD_
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<sys/types.h>
#include<string.h>
#include<time.h>
#define MY_SIZE 100
#define _PATH "."//默认路径为当前目录
using namespace std;
typedef struct msgstru{
long mtype;
char str[MY_SIZE];
}msgstru;(自己定义的msgstru)
int my_mssgget(const char *str);(这里做了一层封装)
#endif
--------------------------------------------
head.c:
#include"head.h"
int my_mssgget(const char *str){
key_t key = ftok(str, 666);//获取一个key值
return msgget(key, IPC_CREAT|IPC_EXCL|0666);
}
-----------------------------------------------
程序A,read.c:
#include"2-16.h"
int main(){
char str[MY_SIZE];
msgstru A;
A.mtype = 1;
int msqid = my_mssgget(_PATH);
int i = 3;
while(i >= 1){
ssize_t pos = read(0,A.str, MY_SIZE/2);
(A.str)[pos-1] = 0;
if ( msgsnd(msqid,&(A.str), pos, 0) == -1){
perror("write error");
exit(0);
}
i--;
}
printf("write stop\n");
sleep(10);
while(i >= -1) {
if ( msgrcv(msqid,&(A.str),MY_SIZE/4, 0, 0) == -1){
perror("read error");
exit(0);
}
printf("%s\n", A.str);
i--;
}
return 0;
}
----------------------------------------------
程序B,read.c:
#include"head.h"
int main(){
msgstru A;
A.mtype = 1;
key_t key = ftok(".", 666);
int msqid = msgget(key, 0);
sleep(10);
int i = 3;
while(i >= 1){
if (msgrcv(msqid, &(A.str), MY_SIZE/4, 0, 0)== -1){
printf("no message");
break;
}
printf("%s\n", A.str);
i--;
}
printf("will write\n");
while(1){
fflush(stdin);
ssize_t pos = read(0, A.str, MY_SIZE/2);
(A.str)[pos-1] = 0;
if (msgsnd(msqid, &(A.str), pos, 0) == -1){
perror("write error");
exit(0);
}
}
return 0;
}