消息队列以链表的方式将消息存储于内核中,调用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. Web前端测试题

    JS题目: 在JavaScript中( )方法可以对数组元素进行排序. A. add()B. join()C. sort()D. length() 答案:http://hovertree.com/ti ...

  2. 关于c++数的进制的经验

    默认状态下,数据按十进制输入输出.如果要求按八进制或十六进制输入输出,在cin或cout中必须指明相应的数据形式,oct为八进制,hex为十六进制,dec为十进制. 注意: 1.使用不带.h的头文件& ...

  3. 重新想象 Windows 8 Store Apps (59) - 锁屏

    [源码下载] 重新想象 Windows 8 Store Apps (59) - 锁屏 作者:webabcd 介绍重新想象 Windows 8 Store Apps 之 锁屏 登录锁屏,获取当前程序的锁 ...

  4. 译 PrestaShop开发者指南 第四篇 深入PrestaShop核心开发

    ## 访问数据库 ### 数据库结构 PrestaShop的数据库表默认带有ps_的前缀,前缀在安装时可以自定义. 所有表名都是小写,以下划线分割.当一个表表示要在两个实体间建立连接时,表名中两个实体 ...

  5. STL---Codeforces675D Tree Construction(二叉树节点的父亲节点)

    Description During the programming classes Vasya was assigned a difficult problem. However, he doesn ...

  6. linux怎么模糊查找一个文件

    linux如何模糊查找一个文件 在当前目录下搜索指定文件: find . -name test.txt 在当前目录下模糊搜索文件: find . -name '*.txt' 在当前目录下搜索特定属性的 ...

  7. SQL SERVER获取数据库文件信息

        MS SQL SERVER 获取当前数据库文件等信息,适用于多个版本: SELECT dbf.file_id AS FileID , dbf.name AS [FileName] , s.fi ...

  8. BaseServlet

    1. 目的: 将提升Servlet的处理请求的能力,而不只限于doGet()/doPost()等请求. 让其Servlet能够自己根据请求,从而触发相应的方法进行处理. 2. 具体代码实现: impo ...

  9. Win10 FaceAPI小demo开发问题汇总

    Win10 FaceAPI小demo开发问题汇总 最近使用微软牛津计划做一个小demo,使用FaceAPI做一个小应用,实现刷脸的功能.开发的过程中用到几个问题,具体如下: Stream 与IRand ...

  10. andriod 读取网络图片

    来自:http://blog.csdn.net/jianghuiquan/article/details/8641283 Android手机上,我们常用ImageView显示图片,我们本章获取网络图片 ...