POSIX消息队列

3.2 POSIX消息队列

​ 消息队列可以认为是一个链表。进程(线程)可以往里写消息,也可以从里面取出消息。一个进程可以往某个消息队列里写消息,然后终止,另一个进程随时可以从消息队列里取走这些消息。这里也说明了,消息队列具有随内核的持续性,也就是系统不重启,消息队列永久存在。

3.2.1 创建(并打开)、关闭、删除一个消息队列
#include <fcntl.h>           /* For O_* constants */
#include <sys/stat.h>        /* For mode constants */
#include <mqueue.h>

mqd_t mq_open(const char *name, int oflag);
mqd_t mq_open(const char *name, int oflag, mode_t mode,
                     struct mq_attr *attr);

/*  
函数说明:函数创建或打开一个消息队列,创建后,在/dev/mqueque下可以看到对应文件
返回值:成功返回消息队列描述符,失败返回-1,错误原因存于errno中 
name: 文件路径,必须以/开头,而且有且只有一个/
oflag: 与open的打开标志一样,加上O_CREAT标志,能够创建消息队列
mode: 与open的打开mode一样
attr: 创建消息队列的时候需要,指定消息队列大小消息个数等,为NULL表示使用默认参数
*/ 
/*消息队列属性结构体*/
struct mq_attr { 
   long mq_flags;       /* Flags: 0 or O_NONBLOCK */ 
   long mq_maxmsg;      /* Max. # of messages on queue */ 
   long mq_msgsize;     /* Max. message size (bytes) */ 
   long mq_curmsgs;     /* # of messages currently in queue */ 
};

mqd_t mq_close(mqd_t mqdes);
/*  
函数说明:关闭一个打开的消息队列,表示本进程不再对该消息队列读写  
返回值:成功返回0,失败返回-1,错误原因存于errno中  
*/  

int mq_unlink(const char *name);
/*  
函数说明:删除一个消息队列,好比删除一个文件,其他进程再也无法访问  
返回值:成功返回0,失败返回-1,错误原因存于errno中  
*/

需要注意:

​ 消息队列的名字最好使用“/”打头,并且只有一个“/”的名字。否则可能出现移植性问题;它必须符合已有的路径名规则(最多由PATH_MAX个字节构成,包括结尾的空字节)。

3.2.2 Posix消息队列读写

消息队列的读写主要使用下面两个函数:

#include <mqueue.h>  


int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio); 
/*
功能:发送一条消息到队列
mqdes:消息队列文件描述符
msg_ptr: 消息内容
msg_len: 内容长度
msg_prio: 消息优先级,它是一个小于MQ_PRIO_MAX的数, 数值越大,优先级越高
返回:若成功则为消息中字节数,若出错则为-1 
*/ 


ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio);  
/*
功能:从队列接收一条消息
mqdes:消息队列文件描述符
msg_ptr: 消息内容
msg_len: 内容长度
msg_prio: 消息优先级
返回:若成功则为0, 若出错则为-1
*/ 

源码sendmq.c

#include <stdio.h>  
#include <string.h>
#include <stdlib.h>  
#include <mqueue.h>  
#include <sys/types.h>  
#include <sys/stat.h>  
#include <unistd.h>  
#include <fcntl.h>  
#include <errno.h>  
   
void error_print(const char* msg)
{
     perror(msg);   
     exit(-1);  
}

/*向消息队列发送消息,消息队列名及发送的信息通过参数传递*/ 
int main(int argc, char *argv[])  
{  
    const char* mqname = "/mymq";
    char buf[] = "helloworld";
    mqd_t mqd;
    int ret;
        
    //只写模式找开消息队列,不存在就创建  
    mqd = mq_open(mqname, O_WRONLY | O_CREAT, 0666, NULL);  
    if(mqd < 0)  
        error_print("mq_open");
   
    /*向消息队列写入消息,如消息队列满则阻塞,直到消息队列有空闲时再写入*/ 
    ret = mq_send(mqd, buf, strlen(buf) + 1, 10);  
    if(ret < 0)  
        error_print("mq_send");
  
    ret = mq_close(mqd);
    if(ret < 0)
        error_print("mq_close");
    return 0;  
} 

编译:

gcc -o sendmq sendmq.c -lrt

运行后可以在/dev/mqueue下看到mymq文件。

源码recvmq.c

#include <stdio.h>  
#include <stdlib.h>  
#include <mqueue.h>  
#include <sys/types.h>  
#include <sys/stat.h>  
#include <unistd.h>  
#include <fcntl.h>  
#include <errno.h>  
void error_print(const char* msg)
{
     perror(msg);   
     exit(-1);  
}
/*读取某消息队列,消息队列名通过参数传递*/ 
int main(int argc, char *argv[])  
{  
    const char* mqname = "/mymq";
    mqd_t mqd;  
    struct mq_attr attr;  
    char *buf;  
    unsigned int prio;  
    int ret;  

    /*只读模式打开消息队列*/ 
    mqd = mq_open(mqname, O_RDONLY);  
    if(mqd < 0)  
         error_print("mq_open");   

    /*取得消息队列属性,根据mq_msgsize动态申请内存*/
    ret = mq_getattr(mqd, &attr);  
    if(ret < 0)  
        error_print("mq_getattr");  

    /*动态申请保证能存放单条消息的内存*/ 
    buf = (char*)malloc(attr.mq_msgsize);  
    if(NULL == buf)  
         error_print("malloc");  

    /*接收一条消息*/ 
    ret = mq_receive(mqd, buf, attr.mq_msgsize, &prio);  
    if(ret < 0)  
        error_print("receive"); 
    
    printf("read data %s  priority %u\n", buf, prio);  
  
    ret = mq_close(mqd);
    if(ret < 0)
        error_print("mq_close");
  
 /*消息队列使用完后就可以删除
    ret = mq_unlink(mqname);
    if(ret < 0)
        error_print("mq_unlink");
  */
    free(buf);
    return 0;  
} 

编译并执行:

gcc -o recvmq recvmq.c -lrt

  

需要注意的是:当消息不断发送,达到消息队列容量最大值的时候,mq_send将阻塞,知道消息队列被接收走,如果消息还未接收,就把消息队列文件删除,则消息丢失。

3.2.3 消息队列的属性
Posix消息队列的属性使用如下结构存放:
struct mq_attr  
{  
    long mq_flags; /*阻塞标志位,0为非阻塞(O_NONBLOCK)*/ 
    long mq_maxmsg; /*队列所允许的最大消息条数*/ 
    long mq_msgsize; /*每条消息的最大字节数*/ 
    long mq_curmsgs; /*队列当前的消息条数*/ 
}; 
/*
队列可以在创建时由mq_open()函数的第四个参数指定mq_maxmsg,mq_msgsize。 如创建时没有指定则使用默认值,一旦创建,则不可再改变。
队列可以在创建后由mq_setattr()函数设置mq_flags 
*/

#include <mqueue.h>  

/*取得消息队列属性,放到mqstat中*/ 
int mq_getattr(mqd_t mqdes, struct mq_attr *mqstat);  

/*设置消息队列属性,设置值由mqstat提供,原先值写入omqstat中,只是用来改变O_NONBLOCK标志*/ 
int mq_setattr(mqd_t mqdes, const struct mq_attr *mqstat, struct mq_attr *omqstat);  

均返回:若成功则为0,若出错为-1 

获取消息队列的属性:

attrmq.c

#include <stdio.h>  
#include <stdlib.h>  
#include <mqueue.h>  
#include <sys/types.h>  
#include <sys/stat.h>  
#include <unistd.h>  
#include <fcntl.h>  
#include <errno.h>  
   
void error_print(const char* msg)
{
     perror(msg);   
     exit(-1);  
}
int main()  
{  
    mqd_t mqd;  
    int ret;  
    struct mq_attr mqattr; 
    const char* mqname = "/mymq";
    /*只读模式打开消息队列*/ 
    mqd = mq_open(mqname, O_CREAT | O_RDONLY, 0666, NULL);  
    if(mqd < 0)  
         error_print("mq_open");   

    /*取得消息队列属性*/
    ret = mq_getattr(mqd, &attr);  
    if(ret < 0)  
        error_print("mq_getattr");  

    printf("nonblock flag:%ld\n", attr.mq_flags);  
    printf("max msgs:%ld\n", attr.mq_maxmsg);  
    printf("max msg size:%ld\n", attr.mq_msgsize);  
    printf("current msg count:%ld\n", attr.mq_curmsgs);  
   
    ret = mq_close(mqd);
    if(ret < 0)
        error_print("mq_close");
 
    ret = mq_unlink(mqname);
    if(ret < 0)
        error_print("mq_unlink");

    return 0;  
} 

编译并执行:

gcc -o attrmq attrmq.c -lrt

设置消息队列的属性:

源码setarrtmq.c

#include <stdio.h>  
#include <stdlib.h>  
#include <mqueue.h>  
#include <sys/types.h>  
#include <sys/stat.h>  
#include <unistd.h>  
#include <fcntl.h>  
#include <errno.h>  
       
void error_print(const char* msg)
{
     perror(msg);   
     exit(-1);  
}
int main()  
{  
    mqd_t mqd;  
    int ret;  
    const char * mqname = "/mymq";
    struct mq_attr mqattr;  
    mqattr.mq_maxmsg = 10; 
    mqattr.mq_msgsize = 8192;  

    mqd = mq_open(mqname, O_RDWR | O_CREAT, 0666, &mqattr);  

    if(mqd < 0)  
    {  
        perror("mq_open");  
        exit(1);  
    }  
    
    mqattr.mq_flags = O_NONBLOCK;  
    mq_setattr(mqd, &mqattr, NULL);// mq_setattr()只关注mq_flags  
       
    /*取得消息队列属性*/
    ret = mq_getattr(mqd, &mqattr);  
    if(ret < 0)  
        error_print("mq_getattr");  
  
    printf("nonblock flag:%ld\n", mqattr.mq_flags);  
    printf("max msgs:%ld\n", mqattr.mq_maxmsg);  
    printf("max msg size:%ld\n", mqattr.mq_msgsize);  
    printf("current msg count:%ld\n", mqattr.mq_curmsgs);   
   
    ret = mq_close(mqd);
    if(ret < 0)
        error_print("mq_close");
         
    return 0;  
} 

编译运行:

gcc -o setattrmq setattrmq.c -lrt

消息队列系统限制查看:

cat /proc/sys/fs/mqueue/msg_max #查看消息队列的消息最大长度
cat /proc/sys/fs/mqueue/msgsize_max #查看消息队列的消息最大个数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值