系统调用函数
int msgget(key_t key, int msgflg);
int msgctl(int msqid,int cmd,struct msqid_ds *buf);
int msgsnd(int msqid,struct msgbuf *msgp,size_t msgsz,int msgflg);
sszie_t msgrcv(int msqid,struct msgbuf *msgp,size_t msgsz,long msg_typ,int msgflg);
相关头文件:<sys/types.h>, <sys/ipc.h>, <sys/msg.h>, <stdio.h>
1. int msgget ( key_t key, int msgflag )
功能:创建或获取标识为key的消息队列,并返回队列描述符。
返回:正确返回该消息队列的描述符msgid;错误返回-1。
参数:
key:消息队列标识符,为正整数。可由用户指定(适用于不同进程家族);也可使用IPC_PRIVATE由系统产生key值(适用于同一进程家族);
msgflag:标志或访问方式,由操作权限和控制命令进行或运算得到。
操作权限:三位数字对应 读/写/执行 0777=》111 111 111(2) 可读可写可执行
控制命令:IPC_CREAT(值0001000),若队列不存在则创建。
2. int msgctl( int msgid, int cmd, struct msqid_ds *buf )
功能:查询、设置消息队列的状态;撤消消息队列。
返回:函数调用成功返回0,不成功返回-1。
参数:
msgid:该消息队列id;
cmd:规定命令的类型:
IPC_STAT 查询消息队列状态,将消息队列的msqid_ds复制到buf;
IPC_SET 设置或修改消息队列状态,设置有效用户、组标识、操作允许权、字节数;
IPC_RMID 撤消描述符为msgid的消息队列;
buf:含有控制参数或查询结果的用户缓冲区的地址,可为0。
3. int msgsnd( int msgid, const void *msgp, size_t msgsz, int msgflag)
功能:将msgp->msgbuf中的消息复制到msgid消息队列中,将之挂到队尾,唤醒等待消息的进程。
参数:
msgid:执行msgget()返回的消息队列的描述符;
msgp:待发送的消息;
msgsz:由msgp指向的数据结构中消息长度,不包括类型type的长度;
msgflag:规定当消息队列满时应执行的动作,例如:若在flag中设置了IPC_NOWAIT,则当消息队列中的字节数超过最大值时(MSGMAX=8192),msgsnd立即返回,否则msgsnd睡眠。flag可置0。
struct msgbuf {
long mtype; //消息类型
char mtext[1]; //消息数据,可以是其他结构
}
4. int msgrcv( int msgid, const void *msgp, size_t msgsz, long msgtype, int msgflag)
功能:从msgid消息队列中接收一个消息:将消息复制到msgp->msgbuf中,并从队列中删除此消息,若消息未到则调用进程阻塞插入等待消息队列尾。
参数:
msgid—消息队列id;
msgp—存放接收消息的用户缓冲区的首地址;
msgsz —要接收字节数(一般为msgp中数据数组的大小),如果使用msgflag = MSG_NOERROR则小于实际的部分会被舍弃;反之会返回-1,errno=E2BIG,且消息依旧保存在消息队列中.
msgtype—接收消息类型:
=0–接收队列的第一个消息;
>0–接收类型为type的第一个消息,若指定MSG_EXCEPT则消息队列中第一个即使类型不符也会被读取;
<0—接收第一个类型小于或等于|type|的消息。
msgflag:若该队列无消息,内核应当做什么,可置0(阻塞)。
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<string.h>
#include<stdlib.h>
struct message {
long type;
char text[128];
} msg;
int isReady = 0;
int isExit = 0;
void setReady(int signal) {
isReady = 1;
}
void setExit(int signal) {
isExit = 1;
}
int main(int argc, char* argv[]) {
key_t key = 113; //随机值
int status = 0;
pid_t pid = fork(); //创建子进程
signal(12, setReady); //自定义信号
if(pid == 0) {
int msgqid = msgget(key, 0777 | IPC_CREAT);
if(msgqid == -1) {
printf("create message queue fail.\n");
exit(1);
}
char childString[50] = "message from child.";
msg.type = 1;
strcpy(msg.text, childString);
status = msgsnd(msgqid, &msg, sizeof(char) * strlen(childString), 0);
if(status == -1) {
printf("send message fail.\n");
exit(1);
}
kill(getppid(), 12); //通知父进程可以读消息队列
while(isReady == 0) { //等待父进程通知
usleep(10);
}
status = msgrcv(msgqid, &msg, sizeof(char) * 128, getpid(), 0);
if(status == -1) {
printf("receive message fail.\n");
exit(1);
}
printf("child: receive message from parent: %s\n", msg.text);
msgctl(msgqid, IPC_RMID, 0);
} else if(pid > 0) {
while(isReady == 0) { //等待子进程通知
usleep(10);
}
int msgqid = msgget(key, 0777 | IPC_CREAT);
if(msgqid == -1) {
printf("create message queue fail.\n");
exit(1);
}
char parentString[50] = "message from parent.";
status = msgrcv(msgqid, &msg, sizeof(char) * 128, 1, 0);
if(status == -1) {
printf("receive message fail...\n");
exit(1);
}
printf("parent: receive message from child: %s\n", msg.text);
msg.type = pid;
strcpy(msg.text, parentString);
status = msgsnd(msgqid, &msg, sizeof(parentString), 0);
if(status == -1) {
printf("send message fail.\n");
exit(1);
}
kill(pid, 12); //通知子进程可以读消息队列
} else {
printf("create child process fail.\n");
exit(1);
}
return 0;
}
通过信号机制通知父子进程读取消息队列的数据
ipcs -q 查看系统中的消息队列,、
ipcrm -q msgqid 删除消息队列
运行结果: