IPC消息队列 -- (Linux系统编程)

|# 1. 消息队列

  • 背景

管道和套接字比较适合两三个进程之间的通信,如果进程成倍增加,管道和套接字的数量也会阶乘级的增加,管理也非常复杂麻烦。于是出现的消息队列

  • 比喻

回转寿司在这里插入图片描述

  • 优先级

让列宁同志先走

  • 本质

内核链表

2. POSIX消息列表

在这里插入图片描述

2.1 查看

  • POSIX消息队列预览:man mq_overview
  • 查看POSIX消息队列:ls /dev/mqueue
  • cat /dev/mqueue/PIC名字

2.2 接口

  • 头文件:mqueue.h
  • 库:librt.so(real time)

2.3 结构体

  • struct mq_attr消息队列属性
成员含义说明
mq_flags标志在mq_open时被初始化,在mq_setattr设置,其值为0或者O_NONBLOCK
mq_maxmsg队列的消息个数最大值只能在mq_open时被初始化
mq_msgsize队列每个消息长度的最大值只能在mq_open时被初始化
mq_curmsgs当前队列消息个数在mq_getattr获取

2.4 函数

POSIX 消息队列主要有八个操作

操 作函数
创建消息队列mqd_t mq_open(const char *name,int oflag,mode_t mode,struct mq_attr)
删除消息队列int mq_unlink(const char *name)
打开消息队列mqd_t mq_open(const char *name,int oflag)
关闭消息队列int mq_close(mqd_t mqdes)
发送消息int mq_send(mqd_t mqdes,const char *msg_ptr,size_t mas_len,unsigned msg_prio)
接收消息ssize_t mq_receive(mqd_t mqdes,char *masg_ptr,size_t msg_len,unsigned *msg_prio)
设置消息队列int mq_setattr(mqd_t mqdes,struct mq_attr *newattr,struct mq_attr *oldattr)
获取消息队列属性int mq_getattr(mqd_t mqdes,struct mq_attr *attr)

2.4.1 创建消息队列

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

在这里插入图片描述

示例!!!
#include<stdio.h>//perror()
#include<mqueue.h>//mq_open()
#define FILE_MODE(S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH)//0644
int main(){
     struct mq_attr attr;
     attr.mq_masmsg=100;
     attr.mq_msgsize=200;
     mqd_t mqd=mq_open("/tem.test",O_CREAT,FILE_MODE,&attr);
     if(-1==mqd){
        perror("mq_open error");
        return 1;
        }
   }

注意:编译时可能需要加上 -lrt

注:

POSIX消息队列的名字所创建的真正路径名和具体的系统实现有关,关于具体POSIX IPC的名字规则可以参考《UNIX 网络编程 卷2:进程间通信》。在Redhat所创建的POSIX消息队列不会在文件系统中创建真正的路径名。且POSIX的名字只能以一个/开头,名字中不能包含其他的/

2.4.2 删除消息队列

int mq_unlink(const char *name (posix IPC名字))
返回值含义
-10
出错成功
示例
#include<mqueue.h>
int main(){
   mq_unlink("/tmp.test");
   }

2.4.3 打开消息队列

mqd_t mq_open(const char *name,int oflag)
  • 参数
参数含义
nameposix IPC名字
oflag标志,O_RDONLY只读;O_RDWR读写;O_WRONLY只写
在这里插入图片描述
  • 返回值
返回值含义
-1出错
其他描述符
示例
#include <stdio.h> // perror()
#include <mqueue.h> // mq_open()
int main(){
    mqd_t mqd = mq_open("/tmp.test",O_RDONLY);
    if(-1 == mqd){
        perror("mq_open error");
        return 1;
    }
    return 0;
}

2.4.4 关闭消息队列

int mq_close(mqd_t mqdes消息队列描述符)
返回值含义
-10
出错成功
示例
#include <stdio.h> // perror()
#include <mqueue.h> // mq_open() mq_close()
int main(){
    mqd_t mqd = mq_open("/tmp.test",O_RDONLY);
    if(-1 == mqd){
        perror("mq_open error");
        return 1;
    }
    // ...
    mq_close(mqd);
}
  • 注意

mq_close()和文件的close()类似,关闭后,消息队列并不从系统中删除。一个进程结束,会自动调用关闭打开着的消息队列。

2.4.5 发送消息

int mq_send(mqd_t mqdes消息队列描述符,const char *msg_ptr消息的指针,size_t msg_len消息长度,不能大于属性值mq_msgsize的值,unsigned msg_prio优先级,小于MQ_PRIO_MAX,数值越大,优先级越高)
示例
#include <stdio.h> // perror()
#include <mqueue.h> // mq_open() mq_send() mq_close()
int main(int argc,char* argv[]){
    mqd_t mqd = mq_open("/tmp.test",O_WRONLY); // 可以设置O_NONBLOCK
    if(-1 == mqd){
        perror("mq_open error");
        return 1;
    }
    const char* msg = "HelloWorld";
    if(-1 == mq_send(mqd,msg,sizeof(msg),1)){
        perror("mq_send error");
        mq_close(mqd);
        return 1;
    }
    mq_close(mqd);
    return 0;
}
注意

消息在队列中将按照优先级大小顺序来排列消息
消息队列已满,mq_send()函数将阻塞,直到有可用空间再次允许放置消息。
如果O_NONBLOCK被指定,mq_send()那么将不会阻塞,而是返回EAGAIN错误。

2.4.6 接收消息

ssize_t mq_recesive(mqd_t mqdes消息队列描述符,char *msg_ptr 消息的指针,size_t msg_len消息长度,不能大于属性值mq_msgsize的值,unsigned *msg_prio优先级,消息在队列中将按照优先级大小顺序来排列消息)
返回值含义
-1出错
正数接收到的消息长度
示例
#include <stdio.h> // perror()
#include <mqueue.h> // mq_open() mq_receive() mq_close()
#define FILE_MODE (S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH) //0644
int main(int argc,char* argv[]){
    mqd_t mqd = mq_open("/tmp.test",O_RDONLY);
    if(-1 == mqd){
        perror("mq_open error");
        return 1;
    }
    char buf[BUFSIZ];
    unsigned int prio;
    if(-1 == mq_receive(mqd,buf,BUFSIZ,&prio)){
        perror("mq_send error");
        mq_close(mqd);
        return 1;
    }
    printf("msg:%s\nprio:%d\n",buf,prio);
    mq_close(mqd);
    return 0;
}
注意
  1. POSIX消息队列在调用mq_receive()时总是返回队列中最高优先级的最早消息。
  2. 如果队列空,mq_receive()函数将阻塞,直到消息队列中有新的消息。
  3. 如果O_NONBLOCK被指定,mq_receive()那么将不会阻塞,而是返回EAGAIN错误。

1.4.7 设置消息队列属性

int mq_setattr(mqd_t mqdes消息队列描述符,struct mq_attr *newattr(新属性,只能设置mq_flags:0:NONBLOCK),struct mq_attr *oldattr旧属性)
返回值含义
-10
出错成功
示例
#include <stdio.h> // perror()
#include <string.h> // bzero()
#include <mqueue.h> // mq_open() mq_setattr() mq_close()
int main(){
    mqd_t mqd = mq_open("/tmp.test",O_RDWR);
    if(-1 == mqd){
        perror("mq_open error");
        return 1;
    }
    struct mq_attr new_attr;
    bzero(&new_attr,sizeof(new_attr));
 
    new_attr.mq_flags = O_NONBLOCK;
    struct mq_attr attr;
    if(-1 == mq_setattr(mqd,&new_attr,&attr)){
        perror("mq_setattr error");
        mq_close(mqd);
        return 1;
    }
    printf("flag:%ld,Max msg:%ld,Max msgsize:%ld,Cur msgnun:%ld\n",attr.mq_flags,attr.mq_maxmsg,attr.mq_msgsize,attr.mq_curmsgs);
    mq_close(mqd);
}

2.4.8 获取消息队列属性

int mq_getattr(mqd_t mqdes消息队列描述符,struct mq_attr *attr属性)
返回值含义
-10
出错成功
示例
#include <stdio.h> // perror()
#include <mqueue.h> // mq_open() mq_getattr() mq_close()
int main(){
    mqd_t mqd = mq_open("/tmp.test",O_RDONLY);
    if(-1 == mqd){
        perror("mq_open error");
        mq_close(mqd);
        return 1;
    }
    struct mq_attr attr;
    mq_getattr(mqd,&attr);
    printf("flag:%ld,Max msg:%ld,Max msgsize:%ld,Cur msgnun:%ld\n",attr.mq_flags,attr.mq_maxmsg,attr.mq_msgsize,attr.mq_curmsgs);
   mq_close(mqd);
    return 0;
}
注意
  1. mq_setattr()可以设置的属性只有mq_flags,用来设置或清除消息队列的非阻塞标志。newattr结构的其他属性被忽略。
  2. mq_maxmsgmq_msgsize属性只能在创建消息队列时通过mq_open()来设置。
  3. mq_open()只会设置该两个属性,忽略另外两个属性。 mq_curmsgs属性只能被获取而不能被设置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值