消息队列MSG(多进程ipc):
(1)管道与消息队列都是由内核来管理的进程间通讯机制
(2)消息队列类似于管道却又比管道更加人性化,管道的读端只要是管道里有消息都会将其读走,而消息队列是有选择性地去读取数据,只要不是它想要地都不会读走
(3)当消息队列的写端往消息队列写入数据时,读端还没打开,数据会一直在消息队列中等待它读端打开
进程间通讯(ipc)之消息队列:
1.在任意进程间有选择性地进行通讯的方式
2.发送数据时需要携带一定的消息标志
3.消息队列创建后由于是存在于内核中由内核管理,使用过后需要人工删除以释放资源
4.当一个发送方往消息队列中发送数据时,接收方一直还没接收,数据会一直在消息队列里等待接收方的出现
函数原型
//创建键值函数
//函数头文件
#include <sys/types.h>
#include <sys/ipc.h>
//函数原型
key_t ftok(const char *pathname, int proj_id);
//函数介绍:
/******************************************************** 函数作用:用于创建一个键值, 键值作用 :用于进程间通讯(ipc)时的一个标识符 形参:pathname:路径名-->通过哪一个路径来获得键值 proj_id( project identifier):项目id:即我们指定给它一个8位(一个字节,最大256)的整数, 注:其实可以看成路径下的消息队名为给它的数 返回值: 成功:新生成且未被使用的键值 失败:-1 ********************************************************/
//获取消息队列的id号,也可使用参数在不存在的情况下创建
//函数头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
//函数原型
int msgget(key_t key, int msgflg);
//函数介绍:
/******************************************************** 函数作用:用于获取一个消息队列的id号或者创建一个消息队列 形参:key:键值,通过使用ftok函数创建返回的一个键值 msgflg:所对应的操作: IPC_CREAT :键值key所对应的消息队列不存在则创建 (创建时需要给它一个权限使用方法类似于open函数,在后面使用位或或上操作权限) O_EXCL:键值key对应的消息队列存在则报错 注:当键值key被指定为IPC_PRIVATE时,系统自动分配一个键值来对应消息队列 返回值: 成功:返回消息队列的标识符 失败:-1 ********************************************************/
//消息队列用于发送和接收的函数
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
int msgflg);
/******************************************************** 函数作用: 形参:msqid:通过msgget函数获取到的消息队列id号 msgp:一个自己定义的消息队列结构体的地址 这个结构体一般形式有: struct msgbuf { long mtype; //消息的标识符,且必须大于0 char mtext[1]; //消息正文,数组大小由自己定义 }; 注:结构体第一个元素必须为long类型的标识符!!! msgsz:发送数据的正文的大小,取决于消息队列结构体中mtext数组的大小 msgtyp:消息队列接收函数中用于选择接收的数据的消息标识符 msgflg:参数有 0 :阻塞写入或读取数据 IPC_NOWAIT:往消息队列或写入或读取数据时不阻塞等待 MSG_NOERROR:消息长度超出 msgsz时截断信息且不报错 返回值: msgsnd: 成功: 0 失败:-1 msgrcv: 成功:读取到的字节数 失败:-1 ********************************************************/
//获取或设置删除消息队列函数
//函数头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
//函数原型
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
/******************************************************** 函数作用:获取消息队列属性,设置消息队列属性或删除消息队列 形参:msqid:通过msgget函数获取到的消息队列id号 cmd:IPC_STAT:获取消息队列的属性,储存到struct msqid_ds *buf中 IPC_SET:把消息队列的属性设置为struct msqid_ds *buf中的属性 IPC_RMID:删除消息队列 IPC_INFO:获取当前系统消息队列的限制值信息 MSG_INFO:获取当前系统消息队列的相关资源消耗情况 buf:一个struct msqid_ds类型的变量的地址,这个结构体的成员有: struct msqid_ds { struct ipc_perm msg_perm; //消息队列的所有权和权限 time_t msg_stime; //消息队列最后一次发送信息的时间 time_t msg_rtime; // 最后一次一次接收信息的时间 time_t msg_ctime; // 最后一次更改消息队列状态时间 unsigned long __msg_cbytes; //当前消息队列的数据大小 msgqnum_t msg_qnum; //当前消息队列的消息个数 msglen_t msg_qbytes; //消息队列最大的数据大小 pid_t msg_lspid; //最后一次发送信息的进程id号 pid_t msg_lrpid; //最后一次接收信息的进程id号 }; 返回值: 成功: IPC_STAT:0 IPC_SET:0 IPC_RMID:0 IPC_INFO:内核中记录所有消息队列信息的数组的下标最大值 MSG_INFO:内核中记录所有消息队列信息的数组的下标最大值 失败:-1 ********************************************************/
测试代码:
发送端
/* 消息队列发送 */
#include <stdio.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
//设计消息队列结构体,数组大小为30
struct msgdata
{
long type;
char data[30];
};
int main()
{
//申请一个消息队列结构体变量
struct msgdata msg_sed;
//清空一下结构体变量
bzero(&msg_sed,sizeof(msg_sed));
//产生键值,第二个值可以为随机值,只要前面创建其他队列没有使用过
key_t key = ftok(".",1);
if(key == -1)
{
//创建失败直接退出
perror("ftok failed");
return -1;
}
//创建消息队列给0666权限,返回一个msgid
int msgid = msgget(key,IPC_CREAT | 0666);
if(msgid == -1)
{
//创建失败直接退出
perror("msgget failed");
return -1;
}
//不断发送数据
while(1)
{
//每次发送前清空一下结构体里的内容
bzero(&msg_sed,sizeof(msg_sed));
printf("请输入需要发送的数据:");
//发送类型为1
msg_sed.type = 1;
fgets(msg_sed.data,30,stdin);
//打印一下字符串长度和内容
//printf("%ld\n",strlen(msg_sed.data) );
//printf("%s\n",msg_sed.data );
//往消息队列发送数据
msgsnd(msgid,&msg_sed,strlen(msg_sed.data),0);
}
//删除消息队列
msgctl(msgid,IPC_RMID,NULL);
return 0;
}
/* 消息队列接收 */
#include <stdio.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <unistd.h>
//设计消息队列结构体
struct msgdata
{
long type;
char data[30];
};
int main()
{
//申请一个消息队列结构体变量
struct msgdata msg_rcv;
//
key_t key = ftok("./",1);
if(key == -1)
{
perror("ftok failed");
return -1;
}
//获取消息队列id号,如果不存在则创建
int msgid = msgget(key,IPC_CREAT | 0666);
if(msgid == -1)
{
perror("msgget failed");
return -1;
}
//接收数据
while(1)
{
//每次清空一下结构体变量里的内容
bzero(&msg_rcv,sizeof(msg_rcv));
//msgrcv(msgid,&msg_rcv,30,1,0);
//从消息队列读取数据,并判断是否读取成功
int ret = msgrcv(msgid, &msg_rcv, 30 ,1, 0);
if(ret == -1)
{
perror("error");
}
printf("接收到的数据%s", msg_rcv.data);
}
//删除消息队列
msgctl(msgid,IPC_RMID,NULL);
return 0;
}
测试结果: