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

摘要: 总结了消息队列的定义,详解了使用消息队列的常用函数,最后给出一个实例加深理解。


一、什么是消息队列

    由于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>

编译运行后效果如下:


    这篇帖子就总结到这里,如有不正确地方还请指出,大家共同进步!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值