来源CSDN:
CSDN-专业IT技术社区-登录blog.csdn.net一、概念和原理
消息队列是另一种标准IPC,当然也大概遵循大部分标准
消息队列,它是存放消息(数据)的队列,而队列是先进先出的线性数据结构
换句话说,我们就是利用这个数据结构 进行进程间的通信
消息队列允许多个进程同时读写消息.由于消息可以定义很多类型,取出时可以指定哪个消息类型取出,所以消息队列解决了共享内存多个进程同时读写时数据混乱的问题,只要把消息标定不同的类型即可
二、使用
1)通过ftok获取key
2)通过key 创建/获取 消息队列 ------- msgget
参数:
key - 上一步获取的key
msgflg - 创建标志和权限
IPC_CREAT|0666
成功返回消息队列ID,失败返回-1
3)把消息 存入队列 / 从队列中取出 ----------- msgsnd/msgrcv
参数:msqid - 消息队列IDmsgq - 消息首地址msgsz - 消息长度(消息数据的长度)msgtyp - 用来指定接收什么类型的消息(仅仅接收消息时才有)0:接收任意类型消息(第一个,先进先出)>0:接收类型为msgtyp的特定消息<0:接收类型 小于等于 msgtyp绝对值的小,类型从小到大接收msgflg - 接收/发送 标识0表示阻塞方式操作,接收消息没有消息可接收/发送消息消息队列满了 就会等待直到成功IPC_NOWAIT表示非阻塞方式操作,接收消息没有消息可接收/发送消息消息队列满了 直接返回错误
msgsnd成功返回0,msgrcv成功返回收到消息的消息数据长度,失败都返回-1
另外,消息类型在系统中是未定义的,所以程序员需要在代码中自己定义消息的类型,但是必须按照以下形式:
struct msgbuf {long mtype; /* 消息类型, 必须大于0 */char mtext[1]; /* 消息数据, 即存放的数据 */};
4)不再使用可以删除消息队列 ------- msgctl
参数:msqid - 消息队列IDcmd - 命令IPC_RMID:删除IPC_SET: 修改IPC_STAT: 获取buf - 设置/获取 时 传入/传出 消息队列的信息, 下面是它的数据类型 ,其中可以修改的是uid、gid和mode
msgctl函数成功返回0,失败返回-1
struct msqid_ds {struct ipc_perm msg_perm; /* Ownership and permissions */time_t msg_stime; /* 最后发送消息时间 */time_t msg_rtime; /* 最后接收消息时间 */time_t msg_ctime; /* 最后修改时间 */unsigned long __msg_cbytes; /* 当前使用消息队列空间大小 (nonstandard) */msgqnum_t msg_qnum; /* 当前消息个数 */msglen_t msg_qbytes; /* 消息队列最大长度 */pid_t msg_lspid; /* 最后发送消息的PID */pid_t msg_lrpid; /* 最后接收消息的PID */};struct ipc_perm {key_t __key; /* Key supplied to msgget(2) */uid_t uid; /* Effective UID of owner */gid_t gid; /* Effective GID of owner */uid_t cuid; /* Effective UID of creator */gid_t cgid; /* Effective GID of creator */unsigned short mode; /* Permissions */unsigned short __seq; /* Sequence number */};
消息队列发送端代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>struct MSG{long mtype;char mtext[100];
};int main()
{//1.获取keykey_t key = ftok(".",'x');if(key==-1){perror("ftok");exit(-1);}//2.创建消息队列int msqid = msgget(key,IPC_CREAT|0666);if(msqid==-1){perror("shmget");exit(-1);}//3.发送消息struct MSG msg1;msg1.mtype = 1;//类型1strcpy(msg1.mtext,"liubei");int res = msgsnd(msqid,&msg1,sizeof(msg1.mtext),0);if(res==-1){perror("msgsnd");exit(-1);}msg1.mtype = 2;//类型2strcpy(msg1.mtext,"guanyu");res = msgsnd(msqid,&msg1,sizeof(msg1.mtext),0);if(res==-1){perror("msgsnd");exit(-1);}printf("消息发送成功!n");return 0;
}
消息队列接收端代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <errno.h>extern int errno;struct MSG{long mtype;char mtext[100];
};int main()
{//1.获取keykey_t key = ftok(".",'x');if(key==-1){perror("ftok");exit(-1);}//2.获取消息队列int msqid = msgget(key,0);if(msqid==-1){perror("shmget");exit(-1);}//3.接收消息struct MSG msg1;while(1){//类型-2,方式非阻塞int res = msgrcv(msqid,&msg1,sizeof(msg1.mtext),/*-2*/0,IPC_NOWAIT);//接收完成删除消息队列if(res==-1&&errno==ENOMSG){break;}else if(res==-1&&errno!=ENOMSG){perror("msgrcv");exit(-1);}else{printf("消息类型 = %ld,消息内容 = %sn",msg1.mtype,msg1.mtext);}}msgctl(msqid,IPC_RMID,0);printf("消息队列删除成功!n");return 0;
}
输出如下:
liaowenbindeMacBook-Pro:3 liaowenbin$ ./4msg
消息发送成功!
liaowenbindeMacBook-Pro:3 liaowenbin$ gcc 5msg.c -o 5msg
liaowenbindeMacBook-Pro:3 liaowenbin$ ./5msg
消息类型 = 1,消息内容 = liubei
消息类型 = 2,消息内容 = guanyu
消息队列删除成功!