Linux&Apue(0.5.6):进程间通信的系统IPC方法(消息队列)编程

(一)进程间通信的系统IPC方法(消息队列)编程

(1) 消息队列基础知识

1.1 消息队列的定义

消息队列:在消息的传输过程中保存消息的容器(本质上是位于内核空间的链表,链表的每个节点都是一条消息。消息类型为 0 的链表记录了所有消息加入队列的顺序,除此之外每一条消息都有自己的消息类型,消息类型用整数来表示,而且必须大于 0)。
限制
①每个消息的最大长度是有上限的(MSGMAX)。
②每个消息队列的总的字节数是有上限的(MSGMNB)。
③系统上消息队列的总数也有一个上限(MSGMNI)。
拓展
①什么是消息?
消息:是在两台计算机间传送的数据单位,也可以理解为有边界信息的字节流。下至包含文本字符串,上至包含嵌入对象(不同于字节流,字符流)。

1.2 消息队列涉及函数

系统IPC方法的步骤基本相同。消息队列创建步骤也分为了:创建和访问MQ,发送消息,接收消息,删除MQ

1.2.1 ftok()函数

ftok()函数:系统建立IPC通讯 (消息队列、信号量和共享内存) 时必须指定一个ID值。通常情况下,该id值通过ftok函数得到。

#include <sys/types.h>		//头文件包含
#include <sys/ipc.h>
key_t ftok( const char * pathname,  int id)
参数功能
pathnamepathname:指定的文件名或路径(一般:当前目录))
int idid:子序号(int型,但只有8bits:1~255)

返回值:在一般的UNIX实现中,是将文件的索引节点号取出,前面加上子序号得到。

1.2.2 msgget()函数

msgget()函数:用来创建消息队列ID。

#include <sys/types.h>		//头文件包含
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
参数功能
keyftok()返回的key_t类型键值
msgflg创建标志

参数msgflg两种设置
①IPC_CREAT,不存在则创建,存在则返回已有的mqid。②IPC_CREAT|IPC_EXCL,不存在则创建,存在则返回出错。
返回值
成功:返回一个非负整数的共享内存段的标识码
失败:返回-1,并设置相应errno值。

1.2.3 msgsnd()函数

msgsnd()函数:用来发送一个消息,必须要有写消息队列的权限。

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
参数功能
msgid由msgget函数返回的消息队列 ID
msgp指针,指向要发送的消息结构体类型的变量。限制:①小于系统上限值②以一个long int长整数开始
msgsz发送消息的长度
msgflg控制着当前消息队列满或到达系统上限时将要发生的事情,设置IPC_NOWAIT表示队列满不等待,返回EAGAIN错误(设为0:线程将被阻塞至消息被写入)

返回值
成功:返回0。
失败:返回-1,并设置相应errno值。
msgp指针指向的结构体示例

typedef struct s_msgbuf
{
	long mtype;
	char mtext[512];
} t_msgbuf;

1.2.4 msgrcv()函数

msgrcv()函数:用来从一个消息队列中接收消息。

ssize_t msgrcv(int msgid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
参数功能
msgid由msgget函数返回的消息队列 ID
msgp一个指针,它指向准备接收的消息
msgszmsgp指向的消息长度(这个长度不含保存消息类型的那个long int长整型)
msgtype消息的类型,它可以实现接收优先级的简单形式
msgflg控制着队列中没有相应类型的消息可供接收时将要发生的事

参数msgtype的值设置
①等于0:返回队列第一条信息。
②大于0:返回队列第一条类型等于msgtype的消息。
③小于0:返回队列第一条类型小于等于msgtype绝对值的消息,并且是满足条件的消息类型最小的消息
参数msgflg的值设置
①IPC_NOWAIT:队列没有可读消息不等待,返回ENOMSG错误。
②MSG_NOERROR:消息大小超过msgsz时被截断。
③msgtype>0且msgflg=MSG_EXCEPT:接收类型不等于msgtype的第一条消息。
④0:一直阻塞,直到有信息进入。
返回值
成功:返回实际接收到缓冲区的字符个数。
失败:返回-1,并设置相应errno值。

1.2.5 msgctl()函数

msgctl()函数:用于控制消息队列。

参数功能
msgidmsgget函数返回的消息队列 ID
cmd采取的操作
buf一个结构指针,它指向存储消息队列的相关信息的 buf

参数cmd的值设置
①IPC_STAT:把msqid_ds结构中的数据设置为消息队列的当前关联值。
②IPC_SET: 如果进程有足够的权限,就把消息队列的当前关联值设置为msqid_ds结构中给出的值。
③IPC_RMID:删除消息队列。

(2) 不同进程收发消息编程示例

2.1 不同进程收发消息编程的代码示例

2.1.1 消息发送方的代码示例
#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>

#define FTOK_PATH	"/dev/zero"
#define FTOK_PROJID	0x66

typedef struct s_msgbuf
{
	long	mtype;
	char	mtext[512];
}t_msgbuf;

int main(int argc,char**argv)
{
	key_t		key;
	int		msgid;
	int		i;
	t_msgbuf	msgbuf;
	int		msgtype;

	if((key=ftok(FTOK_PATH,FTOK_PROJID))<0)
	{
		printf("ftok() get IPC token failure:%s\n",strerror(errno));
		return -1;
	}
	//创建消息队列ID
	msgid=msgget(key,IPC_CREAT|0666);
	if(msgid<0)
	{
		printf("msgget() create  msgqueue failure:%s\n",strerror(errno));
		return -2;
	}
	//转化后,打印各值
	msgtype=(int)key;
	printf("key[%d] msgid[%d] msgypte[%d]\n",(int)key,msgid,msgtype);

	for(i=0;i<4;i++)
	{	
		//将获得的队列ID放入msgbuf结构体中
		msgbuf.mtype=msgtype;
		strcpy(msgbuf.mtext,"Ping");
		//发送信息
		if(msgsnd(msgid,&msgbuf,sizeof(msgbuf.mtext),IPC_NOWAIT)<0)
		{
			printf("msgsnd() send message failure :%s\n",strerror(errno));
			break;
		}
		printf("send message:%s\n",msgbuf.mtext);
		sleep(1);
	}
	msgctl(msgid,IPC_RMID,NULL);
	return 0;
}
2.1.2 消息接收方的代码示例
#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>

#define FTOK_PATH	"/dev/zero"
#define FTOK_PROJID	0x66

typedef struct s_msgbuf
{
	long	mtype;
	char	mtext[512];
}t_msgbuf;

int main(int argc,char**argv)
{
	key_t		key;
	int		msgid;
	int		i;
	t_msgbuf	msgbuf;
	int		msgtype;

	if((key=ftok(FTOK_PATH,FTOK_PROJID))<0)
	{
		printf("ftok() get IPC token failure:%s\n",strerror(errno));
		return -1;
	}
	//创建消息队列ID
	msgid=msgget(key,IPC_CREAT|0666);
	if(msgid<0)
	{
		printf("msgget() create  msgqueue failure:%s\n",strerror(errno));
		return -2;
	}
	//转化后,打印各值
	msgtype=(int)key;
	printf("key[%d] msgid[%d] msgypte[%d]\n",(int)key,msgid,msgtype);

	for(i=0;i<4;i++)
	{
		memset(&msgbuf,0,sizeof(msgbuf));	
		//接收信息
		if(msgrcv(msgid,&msgbuf,sizeof(msgbuf.mtext),msgtype,0)<0)
		{
			printf("msgrcv() receive message failure :%s\n",strerror(errno));
			break;
		}
		printf("receive message:%s\n",msgbuf.mtext);
		sleep(1);
	}
	msgctl(msgid,IPC_RMID,NULL);
	return 0;
}
2.1.3 遇到的问题

发送没有问题
在这里插入图片描述
接收出现问题:No message of desired type
在这里插入图片描述
这里提示:没有符合需求类型的消息。
那么,我在想key值是相同的,但是接收方却接收不到信息,可能是接收上出现问题了。
解决一:将msgrcv()函数中的msgflg设为0,让其一直阻塞看看情况怎么样。
先运行接收程序,让其阻塞等待消息:
在这里插入图片描述
再运行发送程序:
在这里插入图片描述
接收程序的结果:
在这里插入图片描述
我们发现,这样就解决了之前的问题了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值