System V IPC & POSIX IPC(一):消息队列


消息队列允许进程之间以消息的形式交换数据,是一种常见的进程之间的通信机制。

1. 消息队列的创建

System V IPC:

int msgget(key_t key, int msgflg);
返回值:message queue identifier on success, or -1 error
参数key:key一般是通过ftok()返回的一个键或者IPC_PRIVATE,IPC_PRIVATE产生的唯一的key在fork调用的父子进程之间比较有用。
参数msgflg:msgflg可取的值有IPC_CREAT、IPC_EXCL,分别表示新建队列、如果同时指定了IPC_CREAT并且指定的key对应的队列已经存在,那么调用就会失败。

POSIX IPC:

mqd_t mq_open(const char *name, int oflag,
                         /* mode_t mode, struct mq_attr attr/);
返回值:message queue descriptor on success, or (mqd_t)-1 on error
参数name:name参数标示出了消息队列,一个可以移植的name命名方式是使用以斜线打头后面跟着一个或多个非斜线字符的名字,如:/mq-msg。
参数oflag:它控制着mq_open()操作的各个方面,可以包含的值O_CREAT、O_EXCL(跟前面msgget中介绍的同样的意义)、O_RDONLY、O_WRONLY、O_RDWR(控制着进程在消息队列上面的访问方式,跟文件打开系统调用open同样的取值和意义)、O_NONBLOCK(以非阻塞模式打开)。
参数mode:mode是一个位掩码,指定了新消息队列的权限。跟文件打开系统调用open同样的取值和意义。
参数attr:是一个mq_attr结构,指定了新消息队列的特性,后面再详细介绍。

从上面的创建过程来看POSIX IPC的消息队列跟我们熟知的文件open()调用很相似,在mq_open创建队列的同时可以同时指定队列的权限,但是System V IPC却不具备这种特性,它只能通过另外的一个调用msgctl来指定队列的权限,后面我们再介绍。

2. 发送消息

System V IPC

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
返回值:On failure return -1,otherwise return 0
参数msqid:上文msgget返回的id。
参数msgp:是由程序员自定义的一个结构体指针,通常的格式如下:
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[]; /* message data */
};
结构体的第一个部分包含了消息类型,消息的剩余部分则是由程序员定义的一个结构,其长度和类型可以是任意的。这里的消息类型在后面消息接收部分我们能看到其作用。
参数msgsz:指定了上文mtext结构中包含的字节数。
参数msgflg:是一组位掩码,用于控制msgsnd的操作,目前只定义了IPC_NOWAIT这一个标记,标示执行一个非阻塞发送操作。在上面POSIX的mq_open()调用中看到POSIX消息队列的非阻塞标志是在新建队列的时候确认的。

POSIX IPC

int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio);
返回值:On failure return -1,otherwise return 0。
参数mqdes:上文mq_open()调用返回的描述符。
参数msg_ptr:指向发送消息缓冲区的指针,类似msgsnd()中msgp结构体的mtext。
参数msg_len:msg_ptr缓冲区的长度。
参数msg_prio:消息的优先级,类似msgsnd()中msgp结构体的mtype,详细的作用见下面的消息接收部分。

System V IPC和POSIX IPC中关于消息的发送最大的不同可能就是消息的类型和优先级之间的区别,这个留待后面来详细区分。

3. 接收消息

System V IPC

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
返回值:成功读取写入msgp->mtext结构中的字节数。
参数msqid:上文msgget返回的id。
参数msgp:同msgsnd中的msgbuf结构体。
参数msgsz:msgp->mtext结构的最大可用空间,如果队列中待删除的消息体大小超过了msgsz字节,那么就不会从队列中删除消息,msgrcv返回E2BIG错误码。
参数msgtyp:读取消息的顺序无需与消息被发送的一致。可以根据mtype字段的值来选择消息,而这个选择过程是由msgtyp参数来控制的。msgtyp可选的值有三种:
    a. 如果msgtyp等于0,那么删除队列中的第一条消息并将其返回给调用进程。
    b. 如果msgtyp大于0,那么将队列中第一条mtype等于msgtyp的消息删除并将其返回给调用进程。通过指定不同的msgtyp,多个进程能够从同一个消息队列中读取消息而不会出现竞争读取同一条消息的情况,我们也可以越过数据进行读取,而无需顺序读取。
    c. 如果msgtyp小于0,那么就会将等待消息当成优先队列来处理。队列中mtype最小并且其值小于等于msgtyp的绝对值的第一条消息会被删除并返回给调用进程。
参数msgflg:位掩码,用来控制msgrcv的操作,可选的值有IPC_NOWAIT、MSG_EXCEPT、MSG_NOERROR。

POSIX IPC

ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio);
返回值:成功读取的字节数。
参数mqdes:前面mq_open()返回的句柄。
参数msg_ptr:指向接收消息的缓冲区。
参数msg_len:接收缓冲区msg_ptr的可用字节数。
参数msg_prio:POSIX消息队列中的每一个消息都有一个非负整数表示的优先级,在发送消息的时候通过msg_prio参数指定。消息在队列中是按照优先级倒序排序的(即0表示优先级最低)。当一条消息被添加到队列中时,它会放置在队列中具有相同优先级的所有消息之后。在消息接收函数mq_receive()中根据msg_prio优先级从消息队列中删除一条优先级为msg_prio、存在时间最长的消息。

上面是System V IPC和POSIX IPC的两个通用的消息发送接口,两者的接口参数都很类似,需要重点区分的就是消息类型、消息优先级参数。
POSIX IPC的消息发送、接收接口还有另外一个超时的版本,mq_timedsend()和mq_timedreceive()函数和mq_send()、mq_receive()几乎完全一样的,唯一的差别在于如果操作无法立即执行,并且没有设置O_NONBLOCK标记,那么在指定的超时达到后函数就会超时返回。
POSIX消息队列和System V消息队列的另外一个重要区别就是POSIX消息队列能够在接收之前为空的队列上有可用消息的异步通知(即队列从空变成非空)。这个特性允许调用者异步的来接收消息,而无需执行一个阻塞调用或者在非阻塞队列上面定期执行mq_receive()调用了。这个消息通知函数是int mq_notify(mqd_t mqdes, const struct sigevent *sevp)。

4. 消息队列的属性控制

每一个消息队列都具有一系列的属性特征,有些是跟队列相关的,有些是系统全局相关的。
System V IPC

int msgctl(int msqid, int cmd, struct msqid_ds *buf);
返回值:Return 0 on success, or -1 on error
参数msqid:上文msgget返回的id。
参数cmd:cmd参数指定了在队列上执行的操作,可选的值如下
    a. IPC_STAT:将与消息队列相关联的msqid_ds数据结构的副本放到buf指向的缓冲区。
    b. IPC_SET:使用buf指向的缓冲区提供的值更新这个消息队列的msqid_ds结构。
    c. IPC_RMID:立即删除消息队列对象及其关联的msqid_ds结构。
    d. IPC_INFO、MSG_INFO、MSG_STAT:linux系统特有的cmd值,可以用这三个cmd值来获取系统所有的System V消息队列。
参数msqid_ds:消息队列的属性结构体,具体的结构体如下:
struct msqid_ds {
    struct ipc_perm msg_perm; /* Ownership and permissions */
    time_t msg_stime; /* Time of last msgsnd(2) */
    time_t msg_rtime; /* Time of last msgrcv(2) */
    time_t msg_ctime; /* Time of last change */
    unsigned long __msg_cbytes; /* Current number of bytes in queue (nonstandard) */
    msgqnum_t msg_qnum; /* Current number of messages in queue */
    msglen_t msg_qbytes; /* Maximum number of bytes allowed in queue */
    pid_t msg_lspid; /* PID of last msgsnd(2) */
    pid_t msg_lrpid; /* PID of last msgrcv(2) */
};
上面结构体的每一个属性可以参考上面的注释。

POSIX IPC

int mq_getattr(mqd_t mqdes, struct mq_attr *attr);
int mq_setattr(mqd_t mqdes, const struct mq_attr *newattr, struct mq_attr *oldattr);
返回值:Return 0 on success, or -1 on error
参数mqdes:前面mq_open()返回的句柄。
参数attr:消息队列的属性结构体,具体如下:
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 */
};

System V IPC POSIX IPC(一):消息队列相关推荐

  1. system v和posix的共享内存对比 共享内存位置

    参考 http://www.startos.com/linux/tips/2011012822078.html 1)Linux和所有的UNIX操作系统都允许通过共享内存在应用程序之间共享存储空间. 2 ...

  2. IPC 共享内存和 消息队列(发送、接收、移除)以及键值的生成

    一.消息对列 消息队列,是消息的链接表,存放在内核中.一个消息队列由一个标识符(即队列ID)来标识. 特点: 消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级.消息队列独立于发送与接收进 ...

  3. 对POSIX和SystemV消息队列优化:用户态消息队列

    在文章<Linux C语言在用户态实现一个低时延通知(eventfd)+轮询(无锁队列ring)机制的消息队列>中介绍了用户态低时延消息队列的实现,下面我们简单介绍优化步骤. 源码链接:h ...

  4. System V与Posix

    System V和BSD   Unix操作系统在操作风格上主要分为System V和BSD(目前一般采用BSD的第4个版本SVR4),前者的代表的操作系统有Solaris操作系统,在Solaris1. ...

  5. 15、system V 与 posix 信号量的简单比较

    1.XSI system V的信号量是信号量集,可以包括多个信号灯(有个数组),每个操作可以同时操作多个信号灯 posix是单个信号灯,POSIX有名信号灯支持进程间通信,无名信号灯放在共享内存中时可 ...

  6. posix自己搭建消息队列_蘑菇街消息系统上云实践

    小编又来啦-本周要推荐给大家的是一篇跟中间件上云相关的技术文章,这里面详细的记录了,蘑菇街自研消息系统上云的全过程,也是市面上开放出来为数不多的企业自研组件上云实践.有相关需求的同学可以好好学习下. ...

  7. 【Linux篇】第十二篇——进程间通信(管道+system V共享内存)

    进程间通信介绍 概念 目的 本质 分类 管道 什么是管道 匿名管道 匿名管道的原理 pipe函数 匿名管道使用步骤 管道读写规则 管道的特点 管道的大小 命名管道 命名管道的原理 使用命令创建命名管道 ...

  8. 消息队列,ftok,

    一.IPC对象. 1. 什么是IPC对象? 在linux下,IPC对象指的是消息队列.共享内存.信号量.如果用户需要使用IPC对象进行进程之间的通信,首先必须要为IPC对象申请对应资源(key值.ID ...

  9. 细说linux IPC(十):system V 消息队列

    [版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet 或 .../gentleliu,文章仅供学习交流,请勿用于商业用途] system V消息队列和posix消息队列类 ...

最新文章

  1. 调用父级方法_通信:找到任意组件实例的findComponents系列方法,5个终极方案
  2. eclipse解决maven编码UTF-8的不可映射字符
  3. 考研常识:研究生单独考试是什么意思?
  4. linux——apache
  5. 使用PyTorch和Albumentations进行数据增强与损失函数
  6. JavaSE 6之脚本引擎让程序如虎添翼
  7. 分享:TreeFrog 1.1 发布,C++ Web 应用开发框架
  8. php必应壁纸 分辨率,Python爬取必应壁纸的代码实例
  9. Linkedin领英如何批量撤回邀请
  10. 算法训练 Beaver's Calculator (蓝桥杯)
  11. 八边形Octagan类(接口)
  12. mysql的primary key_MySQL Primary Key约束
  13. SSL协议和SET协议
  14. AT88SC0104C读写程序
  15. 强化学习蒙特卡洛3.4 | Every-visit 和 First-visit MC
  16. 超全zookeeper知识点与实战
  17. ant jmeter 原理_Ant+Jmeter自动化接口测试
  18. 什么是 BeanDefinition?
  19. 斑马问题答案C语言,斑马的问题
  20. 计算机软考需要多少分

热门文章

  1. D3D中FVF的顺序
  2. 解决Android11 adb push Permission denied
  3. python中for循环流程图_Python中的迭代遍历 for in
  4. 关于淘宝双十二彩票营销一分钟扫描二十万次的思考
  5. 以太坊中gas、gasPrice、gasLimit是什么?
  6. 安卓 theme常用主题
  7. android俄语间距宽,Android中的俄语本地化
  8. 【3分钟秒懂】结合汇编代码解析C函数入参与PowerPC芯片寄存器的关系
  9. 养成这13个好的学习习惯,想不当学霸都难啊
  10. JDK各个版本的新特性