消息队列以链表的方式将消息存储于内核中,调用msgsnd,msgrcv函数往消息队列里面投送,取出指定的消息。

  • 创建一个消息队列

  生成一个消息队列或者获取已有消息队列id

       #include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h> int msgget(key_t key, int msgflg);

msgget函数返回key值对应的消息队列id。

  1. key是一个用来与一个ipc对象进行对应的东西,起到在内核中标识的作用。

  2.返回的id起到的是外部也就是我们应用层的标识作用,例如所有操作消息队列的函数,都是用msgid来唯一确定一个消息队列。

  3.msgflg用来指定消息队列的权限,操作属性,高位为操作属性,地位为操作权限,比如msgflg通常使用的高位值:

    IPC_CREAT:用来创建一个消息队列

    IPC_EXCL:查询由key指定的消息队列释放存在

    IPC_NOWAIT:之后的消息队列操作都为非阻塞

    一个例子 msgget(key, IPC_CREAT|); 创建由key指定的消息队列,操作权限为0666。

         id = msgget(key, ) 得到key值对应的消息队列的id。

  当key值为 IPC_PRIVATE 时,或者key值不为它但是msgflg指定了 IPC_CREAT ,则创建一个新的消息队列,如果这个消息队列不存在时。指定 IPC_PRIVATE 为key值时,总是创建一个新的消息队列,生成的消息队列key值为0。

由此可见获得消息队列操作 ID是很关键的,一般有3种方法获得id:

  1.指定key值为 IPC_PRIVATE ,创建一个新的消息队列,让后将id值写入一个文件,另一个进程读取该文件,获得id值,这样2个进程就可以通过这个消息队列通信了。

  2.手动指定key值为某个值,多个进程都看看得到这个key,这样做的问题就是可能有一个key值和指定key值一样的消息队列存在了,需要处理这样的错误,换一个key值。

  3.使用ftok函数生成一个key,同一个key调用msgget得到的id肯定是相同的。

       #include <sys/types.h>
#include <sys/ipc.h> key_t ftok(const char *pathname, int proj_id);  (proj_id is 1-255)

  ftok函数的实现是通过stat函数获取pathname的st_dev,st_ino成员(部分位)和proj_id(只用低8位)进行组合生成一个key值,这样做的话,只要pathname和proj_id确定,那么key值基本就确定。

  1.但是这个函数依然存在一种可能就是pathname不一样,proj_id一样,仍然得到一个一样的key,这是因为st_dev,st_ino成员数据被截断了,可能刚好保留的数据是相同的。

  2.还有一点就是必须确保pathname这个文件全程都不会被改动,否则A进程获得key之后,在B进程获取key之前,修改pathname这个文件,从而影响st_dev,st_ino,导致B得到的key和A不一样,虽然pathname,proj_id并没有变。

  • 消息队列属性描述

  通过 msgctl可以获得,设置,删除消息队列

       #include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h> int msgctl(int msqid, int cmd, struct msqid_ds *buf);

  它的使用类似io操作中的ioctl。cmd有如下值:

  IPC_STAT:获取由msgid指定的消息队列的描述结构体,存放于buf中。

  IPC_SET:设置消息队列的描述结构体

  IPC_RMID:立刻删除指定key值的消息队列,key值存放于buf结构体中。如果删除后仍有进程读写这个消息队列,则返回EIDRM错误。

一般,如果消息队列出错了,使用IPC_RMID删除消息队列,释放它在内核中占有的资源。

  • 消息的发送和接收

  消息队列是在一定的空间内建立一个链表,每次都将最近一个发送的消息放在队列链表的末尾,当取走一个消息时,它占据的相应空间就释放出来用以给后面要加入的消息使用。

  通过函数msgsnd,msgrcv可以实现对指定消息队列进行消息发送和接收。

       #include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h> int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

  msgsnd:向msgid指定的消息队列末尾追加一个由msgp指向的消息,消息内容大小为msgsz。通常消息通过一个结构体进行描述,一般形式如下:

           struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[]; /* message data */
};

这个结构体可分为2个部分,mtype用以标识消息类型,mtext这个部分就是消息的内容,可以是你想要的描述消息内容的任何形式如数组,结构体等等。msgsnd,msgrcv里面所指定的消息大小msgsz指的是消息结构体内容mtext部分的长度,不包括mtype!消息类型必须大于0,至于为什么,看到msgrcv函数时就可以知道。

  msgflg:通常有2种取值:

    0:默认值,忽略标识位。消息发送时,当消息队列里面的空间超过限制值时,msgsnd将发生阻塞,直到空间腾出来可以满足需求(就是有人读走消息),或者msgid指定的消息队列已被删除,或者捕获一个信号,否则立马返回。

    IPC_NOWAIT:非阻塞,空间不足时不阻塞,而是返回一个错误值EAGAIN

  一个阻塞的msgsnd是可以被信号中断的。中断后返回错误,错误值EINTR。msgsnd函数一旦被信号中断,永远都不会重启调用,即便安装信号处理函数时指定了重启标识SA_RESTART。因此对于一个阻塞的消息队列,要注意对其错误的处理。

  msgrcv:从msgid指定的消息队列里面取出由msgtyp指定类型的消息存放于msgp指向的空间。取出的消息数据大小由msgsz指定。成功时,返回拷贝到mtext中实际的字节数。

  msgtyp有3种情况,用以控制取出消息的方式:

    等于0:取出队列中的第一个消息,这样可以以先进先出的方式取消息(因为msgsnd都是把消息添加到消息队列的最后面)。

    大于0:取出mtype于msgtyp相同的消息。

    小于0:取出消息队列中mtype值小于等于msgtyp绝对值的所有消息中mtype值最小的那个消息。(假设mtype设定为消息的优先级,这种方式可以用于控制消息队列取消息的优先级)

  从上面的描述可以看出这就是为什么消息结构体中mtype值为什么一定要大于0的原因。

  msgflg有多种组合方式:

    0:忽略标识位,当消息队列中无指定消息时阻塞,直到有指定类型消息,或者消息队列被删除,或者被信号中断。后面2种都会返回错误。

    IPC_NOWAIT:非阻塞方式读取消息。无消息时返回ENOMSG

    MSG_NOERROR:如果消息类型匹配上了,但是消息数据大小大于msgrcv指定的msgsz,则返回错误E2BIG。但是如果指定了MSG_NOERROR标识,则过大的消息数据按照msgsz指定的大小截断。

    MSG_EXCEPT:如果msgtyp大于0,指定此标识表示按照先进先出的方式取出第一个非msgtyp的消息。

 

  一个消息队列中的消息大小是可以不一样的,即便是同一类型的消息,这样当消息数据是变长时,避免出现空间的浪费。配合使用MSG_NOERROR和对错误的判断可以提取出同一类型消息中指定长度的消息。

ipc之消息队列的更多相关文章

  1. System V IPC(1)-消息队列

    一.概述                                                    System V三种IPC:消息队列,信号量,共享内存.这三种IPC最先出现在AT&am ...

  2. Linux 进程间通信(一)(经典IPC:消息队列、信号量、共享存储)

    有3种称作XSI IPC的IPC:消息队列.信号量.共享存储.这种类型的IPC有如下共同的特性. 每个内核中的IPC都用一个非负整数标志.标识符是IPC对象的内部名称,为了使多个合作进程能够在同一IP ...

  3. 进程间通信IPC:消息队列,信号量,共享内存

    2015.3.4星期三 阴天 进程间通信:IPC 文件对象:记录文件描述符,文件开关等 IPC标示符:系统全局的流水号两个进程要通信,打开的是唯一的对象进行通讯,通过key操作 XSI IPC:消息队 ...

  4. IPC之消息队列详解与使用

    一.    概念 消息队列就是一个消息的链表.对消息队列有写权限的进程可以向其中按照一定的规则添加新消息:对消息队列有读权限的进程可以从消息队列中读出消息.消息队列是随内核持续的.下面介绍三个概念: ...

  5. System V IPC 之消息队列

    消息队列和共享内存.信号量一样,同属 System V IPC 通信机制.消息队列是一系列连续排列的消息,保存在内核中,通过消息队列的引用标识符来访问.使用消息队列的好处是对每个消息指定了特定消息类型 ...

  6. 进程间通信——XSI IPC之消息队列

    进程间通信XSI IPC有3种:消息队列.共享内存.信号量.它们之间有很多相似之处,但也有各自的特殊的地方.消息队列作为其中比较简单的一种,它会有些什么东西呢,来一起探讨探讨.. 消息队列结构 消息队 ...

  7. 四十九、进程间通信——System V IPC 之消息队列

    49.1 System V IPC 介绍 49.1.1 System V IPC 概述 UNIX 系统存在信号.管道和命名管道等基本进程间通讯机制 System V 引入了三种高级进程间通信机制 消息 ...

  8. UNIX IPC: POSIX 消息队列 与 信号

    POSIX消息队列可以注册空队列有消息到达时所触发的信号,而信号触发对应的信号处理函数. 下面是一份基本的消息队列和信号处理结合的代码(修改自UNIX网络编程:进程间通信) #include < ...

  9. UNIX IPC: POSIX 消息队列

    首先在我的MAC OSX上试了一下虽然有_POSIX_MESSAGE_PASSING的宏定义,但是用gcc编译会提示没有mqueue.h头文件,先放一边.在Ubuntu上使用正常,不过POSIX消息队 ...

随机推荐

  1. java俄罗斯方块游戏代码

    java俄罗斯方块游戏代码: package com; import java.awt.Color; import java.awt.Graphics; import java.awt.event.K ...

  2. JS实现注销功能

    JS实现注销功能,代码如下: <script> window.history.forward(1); </script> 这个代码的用法就是: 比如,我们此时有两个页面:Log ...

  3. IDEA默认常用快捷键

    作为Java的利器,IDEA属实是非常好用,参考网文总结其常用快捷键如下: Ctrl + /(Ctrl + Shift + /):注释或反注释指定的语句.这个是本人最喜欢的,所以排在第一位. Ctrl ...

  4. Java中的Set集合接口实现插入对象不重复的原理

    在java的集合中,判断两个对象是否相等的规则是: 1).判断两个对象的hashCode是否相等 .      如果不相等,认为两个对象也不相等,完毕       如果相等,转入2)(这一点只是为了提 ...

  5. svn的管理与维护要点—纯手工编写

    由于在公司要维护阿里云的linux服务器,我们的svn服务器就安在阿里云上面.所以经常会涉及到svn的维护操作.离职的时候编写交接文档,刚好有充足的时间写一篇说明介绍,此说明纯原创,不是从网上复制,手 ...

  6. 推荐轻量友好的.NET测试断言工具Shouldly

    Shouldly是一个轻量的断言(Assertion)框架,用于补充.NET框架下的测试工具.Shouldly将焦点放在当断言失败时如何简单精准的给出很好的错误信息. Shouldly在GitHub的 ...

  7. [翻译]:SQL死锁-锁的类型

    很久没有写博客了,这里面的原因有很多.最近的一个项目由于客户明确提出要做下性能压力测试,使用的工具就是VS自带的压力测试工具.以前其它项目做压力测试后反馈的其中一个重要问题就是数据库的死锁.没想到我们 ...

  8. mybatis 下划线转驼峰配置

    一直以来,在sqlmap文件中,对于数据库中的下划线字段转驼峰,我们都是通过resultmap来做的,如下: <resultMap id="ISTableStatistics" ...

  9. 关于IE处理margin和padding值超出父元素高度的问题

    两个div,父div有padding值,子div有margin-top值,浏览器在解析实际父子位置关系时,他们之间的距离是父padding+子margin-top.现在把父div设置固定高度,并有意让 ...

  10. Windows Python2.7环境 安装paramiko模块

    Paramiko是用python语言写的一个模块,遵循SSH2协议,支持以加密和认证的方式,进行远程服务器的连接. 举个常见的例子,现有这样的需求:远程连接到Linux服务器,查看上面的日志状态,大家 ...