IPC之消息队列

1.消息队列的使用方法
1.1发送者:
A) 获取消息队列的 ID
B) 将数据放入一个附带有标识的特殊的结构体,发送给消息队列。

1.2接收者:
A) 获取消息队列的 ID
B) 将指定标识的消息读出。

当发送者和接收者都不再使用消息队列时,及时删除它以释放系统资源。

2.API函数

2.1获取消息队列的 ID
在这里插入图片描述
注意:
2.1.1,选项 msgflg 是一个位屏蔽字,因此 IPC_CREAT、IPC_EXCL 和权限 mode 可以用位
或的方式叠加起来,比如:msgget(key, IPC_CREAT | 0666); 表示如果 key 对应的消息队
列不存在就创建,且权限指定为 0666,若已存在则直接获取 ID。

2.1.2,权限只有读和写,执行权限是无效的,例如 0777 跟 0666 是等价的。

2.1.3,当 key 被指定为 IPC_PRIVATE 时,系统会自动产生一个未用的 key 来对应一个新的
消息队列对象。一般用于线程间通信。

2.2发送与接收信息
在这里插入图片描述
在这里插入图片描述
注意:
2.2.1,发送消息时,消息必须被组织成以下形式:

struct msgbuf
{
	long mtype; // 消息的标识
	char mtext[1]; // 消息的正文
};

也就是说:发送出去的消息必须以一个 long 型数据打头,作为该消息的标识,后
面的数据则没有要求。

2.2.2,消息的标识可以是任意长整型数值,但不能是 0L。

2.2.3,参数 msgsz 是消息中正文的大小,不包含消息的标识。

2.3设置或者获取消息队列的相关属性

在这里插入图片描述
注意:
2.3.1,IPC_STAT 获得的属性信息被存放在以下结构体中:

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; /* 最后一个发送消息的进程 PID */
	pid_t msg_lrpid; /* 最后一个接收消息的进程 PID */
};

其中,权限相关的信息用如下结构体来表示:

struct ipc_perm
{
	key_t __key; /* 当前消息队列的键值 key */
	uid_t uid; /* 当前消息队列所有者的有效 UID */
	gid_t gid; /* 当前消息队列所有者的有效 GID */
	uid_t cuid; /* 当前消息队列创建者的有效 UID */
	gid_t cgid; /* 当前消息队列创建者的有效 GID */
	unsigned short mode; /* 消息队列的读写权限 */
	unsigned short __seq; /* 序列号 */
};

2.3.2,当使用 IPC_INFO 时,需要定义一个如下结构体来获取系统关于消息队列的限制值
信息,并且将这个结构体指针强制类型转化为第三个参数的类型。

struct msginfo
{
	int msgpool; /* 系统消息总尺寸(千字节为单位)最大值 */
	int msgmap; /* 系统消息个数最大值 */
	int msgmax; /* 系统单个消息尺寸最大值 */
	int msgmnb; /* 写入消息队列字节数最大值 */
	int msgmni; /* 系统消息队列个数最大值 */
	int msgssz; /* 消息段尺寸 */
	int msgtql; /* 系统中所有消息队列中的消息总数最大值 */
	unsigned short int msgseg; /* 分配给消息队列的数据段的最大值 */
};

2.3.3,当使用选项 MSG_INFO 时,跟 IPC_INFO 一样也是获得一个 msginfo 结构体的信息,
但是有如下几点不同:
成员 msgpool 记录的是系统当前存在的 MSG 的个数总和
成员 msgmap 记录的是系统当前所有 MSG 中的消息个数总和
成员 msgtql 记录的是系统当前所有 MSG 中的所有消息的所有字节数总和

3.例子
两个进程之间通信,一个发送信息,一个接收信息

发送信息进程程序

#include "unistd.h"
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "sys/types.h"
#include "sys/ipc.h"
#include "sys/msg.h"
#include "signal.h"
#include <wiringPi.h> 

#define MSG1 1			//指定标识
#define MSG2 2			//指定标识
#define TEXTSIZE 128	//数据内存大小

struct mybuf
{
	long mytype;
	char msgtext[TEXTSIZE];	
};

int msgid;

void routine1(int signum) 
{
	printf("MSG1 exit handler.\n");
	msgctl(msgid, IPC_RMID, NULL);
	exit(0);
}

int main(int argc, char *argv[])
{
		int i = 0;
		int ret = -1;
		struct mybuf msg;
		
		msgid = msgget(ftok(".", 1), IPC_CREAT | 0666);	//获取消息队列的ID
		if(msgid < 0)	return -1;
		
		signal(SIGINT, routine1);
		
		while(1)		
		{
			msg.mytype = MSG1;
			sprintf(msg.msgtext, "send msg1\n");
			ret = msgsnd(msgid, &msg, strlen(msg.msgtext), 0);	//直到发送完或者发送错误才返回
			if(ret == -1)return -2;								//发送失败
			
			msg.mytype = MSG2;
			sprintf(msg.msgtext, "send msg222\n");
			ret = msgsnd(msgid, &msg, strlen(msg.msgtext), 0);
			if(ret == -1)return -2;
			
			printf("msg file send%d over\n", i++);
			delay(1000); //ms
		}
		exit(0);	//0表示正常退出,同时冲洗缓冲区数据,并执行退出处理函数
}

接收进程程序

#include "unistd.h"
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "sys/types.h"
#include "sys/ipc.h"
#include "sys/msg.h"
#include "signal.h"
#include <wiringPi.h> 

#define MSG1 1			//指定标识
#define MSG2 2			//指定标识
#define TEXTSIZE 128	//数据内存大小

struct mybuf
{
	long mytype;
	char msgtext[TEXTSIZE];	
};

int msgid;

void routine1(int signum) 
{
	printf("MSG222 exit handler.\n");
	msgctl(msgid, IPC_RMID, NULL);
	exit(0);
}

int main(int argc, char *argv[])
{
int i = 0;
		int ret = -1;
		struct mybuf msg;
		
		msgid = msgget(ftok(".", 1), IPC_CREAT | 0666);	//获取消息队列的ID
		if(msgid < 0)	return -1;
		
		signal(SIGINT, routine1);
		
		while(1)		
		{

			ret = msgrcv(msgid, &msg, TEXTSIZE, MSG1, 0);	//等待接受完才返或错误返回
			if(ret == -1)									//接受失败
			{
				printf("recive is failure\n");
				return -2;							
			}	
			printf(" rcv:%s", msg.msgtext);
			
			ret = msgrcv(msgid, &msg, TEXTSIZE, MSG2, 0);
			if(ret == -1)									//接受失败
			{
				printf("recive is failure\n");
				return -2;							
			}
			printf(" rcv:%s", msg.msgtext);
			
			delay(500); //ms
		}
		exit(0);	//0表示正常退出,同时冲洗缓冲区数据,并执行退出处理函数
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值