您的位置:首页 > 运维架构 > Linux

linux应用编程笔记(15)消息队列编程

2015-12-09 17:38 761 查看
摘要: 总结了消息队列的定义,详解了使用消息队列的常用函数,最后给出一个实例加深理解。

一、什么是消息队列

由于linux早期的通信机制只有信号量,但是信号量所能够传递的数据量非常小,并且管道只能传送无格式的字节流,这样就越来越不能满足应用编程的需求,于是消息队列被开发出来克服了这些缺点。

消息队列本质是一个消息链表,可以把消息看做一个记录,其具有特定的格式,进程可以按照一定的规则向其中添加消息,另一些进程则可以根据规则读走这些消息。

消息队列有两个种类:一种是POSIX(可移植操作系统接口)消息队列,一种是system V消息队列,后者目前被大量的使用,其中系统V消息队列是随着内核持续的,只有在内核重启和人工删除的时候,该消息队列才会被删除。

二、使用消息队列的函数

1.创建键值函数

key_t ftok(char* fname,int id);

那么这个ftok是如何工作的呢?两个参数,一个是我们要使用的文件名,另一个是我们的项目id,一般id不要为0即可。ftok会根据这个两个数字组合成一个键值,当ab进程使用的时候根据文件名和项目id就会访问到相同的消息队列集合,这部分在前面信号量互斥编程的时候总结过,不多做赘述。

2.打开/创建消息队列

函数名:msgget

函数原型:int msgget(key_t key, int msgflg);

函数功能:获取消息队列的标识符

当key键值指定的信号量集合不存在,并且msgflg等于IPC_CREAT的时候,就创建消息队列,并和键值关联,返回与之对应的标识符。

头文件:#include <sys/types.h> #include<sys/ipc.h> #include <sys/msg.h>

返回值:成功返回与key对应的消息队列的标识符,失败返回-1

参数说明

1.key_t key

由ftok获得,键值

2.int msgflg

标志位,主要有以下几个取值,IPC_CREAT,创建新的消息队列,IPC_EXCL,与IPC_CREAT一同使用,如果要创建的消息队列已经存在,则返回错误。IPC_NOWAIT读写消息队列无法满足的时候,不阻塞进程。

以下两种情况,将创建一个新的消息队列:第一,如果没有与key键值对应的消息队列,并且msgflg的值包含IPC_CREAT,就创建。第二,key的flg为IPC_PRIVATE。

3.发送消息

函数名:msgsnd

函数原型:int msgsnd(int msqid,const void *msgp,size_tmsgsz,int msgflg);

函数功能:向消息队列中发送一条消息。

头文件:#include <sys/types.h> #include<sys/ipc.h> #include <sys/msg.h>

返回值:成功返回0,失败返回-1。

参数说明

1.int msqid

msgget函数返回的消息队列的标识符。

2.const void *msgp

该指针指向存放消息的结构体,具体结构如下:

struct msgbuf{

long mtype;//消息类型>0

char mtext[1];//消息数据的首地址

}

这里根据mtype的值来取啥名类型的消息,比如1对应一个类型,2对应一个类型,3对应一个类型等等。

3.size_t msgsz

消息数据的长度

4.int msgflg

发送标志,常用的就是IPC_NOWAIT,表示消息队列没有足够空间容纳发送的消息的时候,不阻塞发送消息的进程。

3.接受消息

函数名:msgrcv

函数原型:ssize_t msgsnd(int msqid, void *msgp,size_t msgsz,longmsgtyp,int msgflg);

函数功能:从msqid标识的消息队列中取走一条消息,该消息类型为msgtyp,并把消息存储在msgp指向的msgbuf中。在成功的读取一条消息后,该消息将在消息列表中被删除。

头文件:#include <sys/types.h> #include<sys/ipc.h> #include <sys/msg.h>

返回值:成功返回从数组中读取的消息的字节数,失败返回-1。

参数说明

1.int msqid

msgget函数返回的消息队列的标识符。

2.void *msgp

该指针指向存放消息的结构体,具体结构如下:

struct msgbuf{

longmtype;//消息类型>0

char mtext[1];//消息数据的首地址

}

这里根据mtype的值来取啥名类型的消息,比如1对应一个类型,2对应一个类型,3对应一个类型等等。

3.size_t msgsz

消息数据的长度

4.long msgtyp

要取走的消息的类型

5.int msgflg

发送标志,常用的就是IPC_NOWAIT,表示消息队列没有足够空间容纳发送的消息的时候,不阻塞发送消息的进程。

下面是一个接受消息的例程

<span style="font-size:18px;">int read_message(int qid,long type,structmymsgbuf* qbuf)
{
int result,length;
length=sizeof(structmymsgbuf)-sizeof(long);
if((result==msgrcv(qid,qbuf,length,type,0))==-1)
{
return -1;
}
return result;
}
</span>


4.删除消息队列

函数使用:msgctl(msgid,IPC_RMID,NULL);

返回值:失败返回-1则删除失败,成功返回0.

三、消息队列的使用编程

<span style="font-size:18px;">#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>

struct msg_buf//该机构体是存放消息类型和具体发送数据的
{
int mtype;
char data[255];
};

int main(void)
{
key_t key;
int msgid;
int ret;
struct msg_buf msgbuf;

/*创建键值*/
key=ftok("/home/passionbird/project",'p');
printf("key= %x\n",key);

/*创建消息队列*/
msgid=msgget(key,IPC_CREAT|0666);//将创建的键值给msgget,如果不存在关联的消息队列,就创建,权限为0666

if(msgid == -1)
{
printf("creatmsg error!\n");
return-1;
}

/*发送消息到队列*/
msgbuf.mtype=getpid();//这里使用的消息类型由getpid()给出
strcpy(msgbuf.data,"thisis a msg test demo!");//将消息拷贝到msgbuf的data数组中
ret=msgsnd(msgid,&msgbuf,sizeof(msgbuf.data),IPC_NOWAIT);//msgid是消息队列的标识符,第二个参数是指针,所以把结构体地址给进去,
if(ret== -1)                                            //第三个参数是数据的大小,最后是表示发送不了的时候不阻塞该进程。
{
printf("sendmsg error!\n");
return-1;
}

/*从消息队列读走消息*/
ret=msgrcv(msgid,&msgbuf,sizeof(msgbuf.data),getpid(),IPC_NOWAIT);

if(ret== -1)
{
printf("receive msg error!\n");
return-1;
}

printf("We received message:%s\n",msgbuf.data);//打印出来接收到的消息

ret=msgctl(msgid,IPC_RMID,NULL);//删除消息队列
if(ret!= -1)
{
printf("remove mymsg sucessed!\n");
}

return0;
}</span>


编译运行后效果如下:



这篇帖子就总结到这里,如有不正确地方还请指出,大家共同进步!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: