进程通信之消息队列

目录

  • 消息队列的概念
  • msgsend.c, msgreceive.c
  • 输出
(一)消息队列的概念

定义:是一个消息的链表。可以把消息看作一个记录,具有特定的格式以及特定的优先级。有写权限的进程可以向消息队列中添加新消息;有读权限的进程则可以从消息队列中读走消息。消息本质上是一种数据结构。暂且这样,先要会用,会用了可以继续研究内部实现过程。用都不会用,太纠结实现原理,在有限时间内,是得不偿失的。

(二)通信流程

下面只对用到的函数参数分析及代码解析,最后给一个编程思路。
下面涉及两个文件,msgsend.cmsgreceive.c
基本函数:msgrcv(接收)、msgsnd(发送)、msgget(新建)、msgctl(删除)

msgsend.c

(1)新建消息队列

//创建消息队列--类比于open,其返回的标识id,用于msgrcv(接收)、msgsnd(发送)
int msgget(key_t key, int msgflg);

参数:
(1)key:消息队列关联的标识符,本质是整数,可以弄个整数强制转化下就可以了,如(key_t)1234
(2)msgflg:消息队列的建立标志存取权限

  • IPC_CREAT:如果内核中没有此队列则创建它
  • 当IPC_EXCL和IPC_CREAT一起使用时,如果队列已经存在,则失败
    例如: 用msgget创建一个消息队列
	msg = msgget((key_t)1234, 0777|IPC_CREAT);					//IPC_CREAT没有就创建及存取权限s
	if(msg == -1)
	{
		fprintf(stderr, "The filure code is %d!!!\n",errno);	//errno--number of last error
		exit(EXIT_FAILURE);
	}

(2)消息队列的发送

//消息队列的发送--类比于write
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

参数:

  • msqid : 消息队列的标识码(msgget返回的id)
  • msgp : 指向消息缓冲区的指针,需要用户自己定义一个结构体,系统没有提供(满足第一元素要大于0,第二个数字符数组), 这里是void,要强制转换下,最好这样。
//这个结构体要用户自己写一个,只要第一个参数值大于0,第二个是字符数组,都可以了,如:
#define BUF_TEXT 512
struct msg_st
{
	long msg_type;       										//标志位
	char msg_text[BUF_TEXT];  									//发送数据缓冲区
};

  • msgsz : 消息的长短
  • msgflg: 标志位–如果为0,表示忽略该标志位
  • 返回值–On success, zero is returned. On error, -1 is returned

进程通信之消息队列_第1张图片
//msgsend.c

#include 
#include 
//msgget
#include 
#include 
#include 
//exit头文件
#include 
#include 
//errno头文件
#include 
#include 

#define BUF_TEXT 512


/****************************************************************************************
**									消息队列
** msgget():创建消息队列--类比于open
**	 int msgget(key_t key, int msgflg);
** key:
**	 消息队列关联的标识符
** msgflg:消息队列的建立标志和存取权限
**	 IPC_CREAT:如果内核中没有此队列则创建它
**	 当IPC_EXCL和IPC_CREAT一起使用时,如果队列已经存在,则失败
** RETURN VALUE
** 	 执行成功则返回消息队列的标识符(a nonnegative integer-非负整数),否则返回-1
** 注意:
**		key_t本质是整数,你自己弄个整数强制转化下就可以了,如(key_t)1234	 		
** msgsnd():消息队列的发送--类比于write
** 	 int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
** msqid : 消息队列的标识码(msgget返回的id)
** *msgp : 指向消息缓冲区的指针,需要用户自己定义一个结构体,系统没有提供(满足第一元素要大于0,第二个数字符数组)
** 		   这里是void*,要强制转换下,最好这样。
** msgsz : 消息的长短
** msgflg: 标志位
** RETURN VALUE
**   On success, zero is returned. On error, -1 is returned
** msgrcv():消息队列的接受--类比于read
** 	 ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
** msqid : 消息队列的标识码(msgget返回的id)
** *msgp : 指向消息缓冲区的指针,需要用户自己定义一个结构体,系统没有提供(满足第一元素要大于0,第二个数字符数组)
** 		   这里是void*,要强制转换下,最好这样。
** msgsz : 消息的长短
** msgtyp: msgtyp等于0 ,则返回队列的最早的一个消息
** 		   msgtyp大于0,则返回其类型为mtype的第一个消息
** 		   msgtyp小于0,则返回其类型小于或等于mtype参数的绝对值的最小的一个消息
** msgflg: 标志位,如果为0,表示忽略该标志位
** RETURN VALUE
**   成功返回数据长度,错误返回-1
** fgets():从指定流中读出size-1个字符,若读入新行,则存在buffer中,最后要以NULL结尾
** 	 char *fgets(char *s, int size, FILE *stream);
** stream: 几种标准的流/文件句柄
** stpcpy(): 字符串的复制
** 	 char *stpcpy(char *dest, const char *src);
** strncmp(): 字符串比较
** 	 char *strncmp(char *dest, const char *src, size_t n);
****************************************************************************************/ 

//msgsnd/msgrcv 第二个参数
struct msg_st
{
	long msg_type;       										//标志位
	char msg_text[BUF_TEXT];  									//发送数据缓冲区
};

int main(void)
{
	struct msg_st data;							
	int msg = -1;												//标识id
	int running = 1;
	char buffer[BUFSIZ];										//系统常量BUFSIZ是8192--定义在stdio.h中
	
	msg = msgget((key_t)1234, 0777|IPC_CREAT);					//IPC_CREAT没有就创建及存取权限s
	if(msg == -1)
	{
		fprintf(stderr, "The filure code is %d!!!\n",errno);	//errno--number of last error
		exit(EXIT_FAILURE);
	}
	
	while(running)
	{
		printf("Please enter data: \n");
		fgets(buffer, BUFSIZ, stdin);							// 标准输入向buffer获取BUFSIZ-1个字符
		data.msg_type = 1;										//标志置1,表示要通信了。其他数也可以
		stpcpy(data.msg_text, buffer);							//将buffer的数据复制到结构体的msg_text中
		
		if(msgsnd(msg, (void *)&data, BUF_TEXT, 0) == -1)		//发送数据到data结构体的数组中
		{
			fprintf(stderr, "magsnd error!!!\n");
			exit(EXIT_FAILURE);
		}
		if(strncmp(data.msg_text, "end", 3) == 0)				//判断字符串是否相等,自己弄个结束标志	
		{
			running = 0;										//推出while
		}
		sleep(1);
	}
	exit(EXIT_SUCCESS);	   
}

msgreceive.c

(1)新建消息队列
和msgsend.c一样,都需要打开同一个消息队列才可以通信。见上

(2)消息队列的接收

 msgrcv():消息队列的接受--类比于read
 ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
  • msqid : 消息队列的标识码(msgget返回的id)
  • *msgp : 指向消息缓冲区的指针,需要用户自己定义一个结构体,系统没有提供(满足第一元素要大于0,第二个数字符数组), 这里是void,要强制转换下,最好这样。*—也就是说在msgreceive.c中也要定义一样的结构体。
  • msgsz : 消息的长短
  • msgtyp: msgtyp等于0 ,则返回队列的最早的一个消息,这里给0
    msgtyp大于0,则返回其类型为mtype的第一个消息
    msgtyp小于0,则返回其类型小于或等于mtype参数的绝对值的最小的一个消息
  • msgflg: 标志位–如果为0,表示忽略该标志位

(3)断开消息队列的连接

 msgctl():消息队列的控制函数,里面有一项可以删除消息队列
 int msgctl(int msqid, int cmd, struct msqid_ds *buf);
  • msqid : 消息队列的标识码(msgget返回的id)
  • cmd : IPC_RMID: 立即断开连接
  • 返回值 —On success, IPC_STAT, IPC_SET, and IPC_RMID return 0.On error, -1 is returned
	//断开消息队列的连接
	if(msgctl(msg, IPC_RMID, 0) == -1)										//msgctl删除消息队列
	{
		fprintf(stderr, "magctl error code %d !!!\n",errno);
		exit(EXIT_FAILURE);
	}

进程通信之消息队列_第2张图片

//msgreceive.c

#include 
#include 
//msgget
#include 
#include 
#include 
//exit头文件
#include 
#include 
//errno头文件
#include 
#include 

/****************************************************************************************
**									消息队列
** msgrcv():消息队列的接受--类比于read
** 	 ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
** msqid : 消息队列的标识码(msgget返回的id)
** *msgp : 指向消息缓冲区的指针,需要用户自己定义一个结构体,系统没有提供(满足第一元素要大于0,第二个数字符数组)
** 		   这里是void*,要强制转换下,最好这样。
** msgsz : 消息的长短
** msgtyp: msgtyp等于0 ,则返回队列的最早的一个消息,这里给0
** 		   msgtyp大于0,则返回其类型为mtype的第一个消息
** 		   msgtyp小于0,则返回其类型小于或等于mtype参数的绝对值的最小的一个消息
** msgflg: 标志位,如果为0,表示忽略该标志位
** RETURN VALUE
**   On success, zero is returned. On error, -1 is returned
** msgctl():
**   int msgctl(int msqid, int cmd, struct msqid_ds *buf);
** msqid : 消息队列的标识码(msgget返回的id)
** cmd   : 
**   IPC_RMID: 立即断开连接
** RETURN VALUE
**   On success, IPC_STAT, IPC_SET, and IPC_RMID return 0.On error, -1 is returned
** fgets():从指定流中读出size-1个字符,若读入新行,则存在buffer中,最后要以NULL结尾
** 	 char *fgets(char *s, int size, FILE *stream);
** stream: 几种标准的流/文件句柄
** stpcpy(): 字符串的复制
** 	 char *stpcpy(char *dest, const char *src);
** strncmp(): 字符串比较
** 	 char *strncmp(char *dest, const char *src, size_t n);
****************************************************************************************/

//msgsnd/msgrcv 第二个参数
struct msg_st
{
	long msg_type;       													//标志位
	char msg_text[BUFSIZ];  												//系统常量BUFSIZ是8192--定义在stdio.h中
};


int main(void)
{
	struct msg_st data;
	int msg = -1;															//标识id
	int running = 1;
	char buffer[BUFSIZ];
	long int msgtype = 0;													//这里给0,返回队列的最早的一个消息
	
	//打开消息队列
	msg = msgget((key_t)1234, 0777|IPC_CREAT);								//IPC_CREAT没有就创建及存取权限s
	if(msg == -1)
	{
		fprintf(stderr, "The filure code is %d!!!\n",errno);				//errno--number of last error
		exit(EXIT_FAILURE);
	}
	
	//接受消息队列的数据---以end结束
	while(running)
	{
		if(msgrcv(msg, (void *)&data, BUFSIZ, msgtype, 0) == -1)			//将结构体中数据通过msgrcv接收  
		{
			fprintf(stderr, "magcve error code %d !!!\n",errno);
			exit(EXIT_FAILURE);
		}
		printf("You just wrote:\n%s\n",data.msg_text);
		
		if(strncmp(data.msg_text, "end", 3) == 0)							//以end结束	
		{
			running = 0;
		}
	}
	
	//断开消息队列的连接
	if(msgctl(msg, IPC_RMID, 0) == -1)										//msgctl删除消息队列
	{
		fprintf(stderr, "magctl error code %d !!!\n",errno);
		exit(EXIT_FAILURE);
	}
	exit(EXIT_SUCCESS);	
}
(三)输出

进程通信之消息队列_第3张图片
最后:下面图大致概述了下
进程通信之消息队列_第4张图片

你可能感兴趣的:(进程通信之消息队列)