linux环境消息队列


概述:

进程间通信就像货物托运,不同通信方式代表了不同托运渠道,管道是最古老的一种。但管道出货不能分清货物批次,而消息队列,弥补了这些缺陷:


1. 消息队列是一种先进先出的队列数据结构,可以保证先送出的货物先到达,后送出的货物后到达,避免了插队现象。

2. 消息队列将输出的信息进行打包处理,这样可以保证每个消息为单位进行接收了。

3. 消息队列可以对货物进行分类服务,标记各种类别的货物,这样就可以根据货物类别分别出货,如果顾客只希望领取队列中的A类货物,他可以跳过消息队列头,直接取队列中,最接近队列头处的A类货物,并不影响其他货物。


广义上讲一切能使进程间相互交流的方法都是IPC,比如文件,管道,Socket等。狭义上讲IPC特指消息队列,信号量,共享内存三种对象。

消息队列用于不同进程间少量数据的顺序共享。

信号量用于进程间的同步与互斥的控制。

共享内存应用于进程间大批量数据的随机共享访问。


查询 IPC 对象 :

shell 命令 ipcs 可查当前系统的IPC对象信息 :

ipcs 【opions】

-q  只查询 消息队列 IPC对象

-s 只查询信号量IPC对象

-m只查询共享内存IPC对象

-a 查询IPC对象全部属性

默认 查询 三者基本属性,基于 “”-qsm“”

消息队列简介: 

消息队列是一种先进先出的队列型数据结构,它实际上是系统内核中的一个内部链表,消息队列被顺序插入队列中,其中发送进程将消息添加到队列末尾,接收进程从队列读取消息。



多个进程可以同时向一个消息队列发送消息,也可以同时从一个消息队列中接收消息。发送进程把消息发送至队尾,接收进程从消息队列头部读取消息,消息一旦被独处就从队列中删除。


内核采用msqid_ds来管理消息队列,它的数据成员与命令“”ipcs -a -q“” 中显示的结果一一对应。



消息队列中各个消息存储在结构为msg结构的空间中个,它们组成一个线性的消息链表,其中msgid结构成员msg_first和msg_last 分别指向这个链表的表头和表尾的指针,结构msg的定义如下:

理论上可以通过结构msgid_ds成员msg_first,msg_last和结构msg的成员msg_msg_next遍历整个消息队列并完成管理和维护消息队列的功能,但实际这三个成员是内核直割数据,用户无权引用。



消息结构 : 

消息队列本身由消息类型和消息数据组成,我们常常使用如下结构作为消息模板:

longmtype 指定了消息类型,它的取值为正整数。通常我们可以吧不同功能的消息,分别定义为不同消息类型,这样就可以共享一个消息队列了。


消息数据 :

成员metext制定了消息的数据,实际上只要就够的第一个成员维持long型不变,我们可以定义任意的数据类型甚至包括结构来描述消息数据:



相关函数 :


msgget
作用 : 创建或打开消息队列 .
头文件 : #include<sys/types.h> #include <sys/ipc.h> #include<sys/msg.h>
函数原型 : int msgget(key_t key,int msgflg)
key : 消息队列的键值 ,多个进程可通过他访问同一个消息队列,其中有个特殊值IPC_PRIVATE,
用于创建当前进程的私有消息队列 . 
msgflg : 权限标志位
成功 : 消息队列 ID
出错 : -1

msgsnd
作用 : 添加消息 . 使用的函数是msgsnd() ,它把消息添加到已打开的消息队列末尾 .
头文件 : #include<sys/types.h> #include <sys/ipc.h> #include<sys/msg.h>  
原型 : int msgsnd(int msqid,const void *msgp,size_t msgsz,int msgflg)
msg : 消息队列的队列 ID.
msgp : 指向消息结构的指针 , 该消息结构msgbuf 通常如下 .
struct msgbuf
{
long mtype;  /*消息类型,该结构必须从这个域开始*/
char mtext[1]; /*消息正文 自定大小  应该是*/
}
msgsz : 消息正文的字节数 (不包括消息类型指针变量)
msgflg : IPC_NOWAIT : 若消息无法立即发送(如当前消息队列已满), 函数会立即返回0
0 : msgsnd 调用阻塞直到发送成功为止 .
msgrcv
作用 : 读取消息。使用的函数是msgrcv(),它把消息从消息队列中取走,与FIFO不同的是,这里可以取走指定的某一条消息
函数原型 : int msgrcv(int msqid,void *msgp,size_t msgsz,long int msgtyp,int msgflg)
msqid : 消息队列ID
msgp : 消息缓冲区,同 msgsnd 中的msgp .
msgsz : 消息正文的字节数 .
msgtyp : 0 :接收消息队列中第一个消息 ;大于 0 : 接收消息队列中第一个类型为msgtyp的消息
小于0 : 接收消息队列中第一个类型值 不小于msgtyp绝对值且类型值最小的消息 .
msgtyp 可以以非先进先出次序读消息.
msgflg : IPC_NOWAIT 使操作不阻塞 , 如果没有指定类型的消息可用 ,则 msgrcv 返回 -1 .
msgctl 
作用 :  控制消息队列。它可以完成多项功能。
函数原型 : int msgctl(int msgqid,int cmd,struct msgid_ds *buf)
msqid : 消息队列 的 队列ID
cmd : 命令参数 :IPC_STAT : 读取消息队列的数据结构msqid_ds,并将其存储在buf指定的地址中
IPC_SET : 设置消息队列的数据结构msqid_ds中的ipc_pem域(IPC操作权限描述结构)值 ,这个值取自buf参数
IPC_RMID : 从系统内核中删除消息队列
buf : 描述消息队列的 msqid_ds 结构类型变量
成功 :  0  ;  出错 : -1 ;

 

例 :


发送程序 :
/********************************************************************************
*功能
*   本实验意在展示如何使用消息队列进行两个进程(发送端和接收端)之间的通信,
*   包括消息队列的创建、消息发送与读取、消息队列的撤销和删除等多种操作。
*   消息发送端进程和消息接收端进程不需要额外实现进程间的同步。
*   在本实验中,发送端发送的消息类型设置为该进程的进程号(可以取其他值),
*   因此接收端根据消息类型来确定消息发送者的进程号。注意这里使用了ftok()函数,
*   它可以根据不同的路径和关键字来产生标准的key。
********************************************************************************/
#include <unistd.h>  
#include <sys/types.h>
#include <sys/ipc.h>  
#include <sys/msg.h>  
#include <stdlib.h>  
#include <stdio.h>  
#include <string.h>  


#define BUFFSIZE 128

struct message 
{
	long msg_src; //消息类型
	char msg_text[BUFFSIZE]; //消息正文
};

int main()
{
	
	int qid;      //消息队列ID 
	key_t key;
	struct message msg;
	//根据不同的路径和关键字产生标准的 key
	if(( key = ftok(".",'b')) == -1 )
	{
		perror("frok");
		exit(0);
	}
	//创建消息队列
	if((qid=msgget(key,0666))==-1)
	{
		perror("msgget");
		exit(0);
	}
	
	printf("open queue %d\n",qid);
	
	while(1)
	{
		printf("Enter some message to queue : \n");
		if((fgets(msg.msg_text,BUFFSIZE,stdin))==NULL)
		{
			perror("fgets error");
		}
		
		msg.msg_src = getpid();
		if((msgsnd(qid,&msg,strlen(msg.msg_text),0))<0)
		{
			perror("message posted");
			exit(0);
		}
		if(strncmp(msg.msg_text,"quit",4)==0)
		{
			break ; 
		}
	}
	
	exit(0);

}









接收程序 :

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

#define BUFFSIZE 128

struct message 
{
	long msg_src; //消息进程来源
	char msg_text[BUFFSIZE]; //消息正文
};


int main()
{
	int qid;
	key_t key;
	struct message msg;
	
	if((key = ftok(".",'b')) ==-1 )
	{
		perror("ftok");
		exit(0);
	}
	
	if(( qid = msgget(key,0666|IPC_CREAT)) ==-1 )
	{
		perror("ftok");
		exit(1);
	}
	
	printf("open queue %d\n",qid);
	
	do
	{
		/*读取消息队列*/
		memset(msg.msg_text,0,BUFFSIZE);
		if(msgrcv(qid,(void *)&msg,BUFFSIZE,0,0)<0)
		{
			perror("msgrcv");
			exit(1);
		}
	
		printf("The message from process %ld : %s",msg.msg_src,msg.msg_text);
	
	}while(strncmp(msg.msg_text,"quit",4) < 0);
	
	printf("I Will Remove the queue %d from kernel\n",qid);
	//从系统内核移走消息队列
	if(msgctl(qid,IPC_RMID,NULL)<0)
	{
		perror("msgctl");
		exit(1);
	}
	exit(0);
}







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值