消息队列以链表的方式将消息存储于内核中,调用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. Unity3D入门基本概念整理

    1. (1)在场景中添加资源 只需单击工程视图 (Project View) 中的网格(Mesh)并拖动至层级视图 (Hierarchy) 或场景视图 (Scene View),便可将其添加至场景 ( ...

  2. C#根据CPU+磁盘标号来注册软件

    很多私人软件都需要自己的作品出售给别人只能一台电脑使用,不可以随便一个电脑都可以运行自己的软件,所以就有了软件注册限制的控制,收集了一个注册软件的帮助类,分享记录一下. 功能介绍:    根据CPU+ ...

  3. Studio for WPF:定制 C1WPFChart 标记

    在本篇文章中,我们将阐述如何定制 C1WPFChart 数据点的标记. 下面分步讲解实现: 1.定制自定义样式: 1: <Window.Resources> 2: <Style x: ...

  4. 认识Python

    web框架:Django.Tornado.Flask Twisted:复杂的异步网络框架 指定解释器 #!/usr/bin/env python #!/usr/bin/python print (&q ...

  5. Durandal介绍

         Durandal是一个JS框架用于构建客户端single page application(SPAs).它支持MVC,MVP与MVVM前端构架模式.使用RequireJS做为其基本约定层,D ...

  6. FlexPaper 2.2.1介绍与提取嵌入的文档

            源起看到某个公司内网的公文使用FlexPaper组件来显示文档,在这儿是GoogleCode Project的主页, 还有现在的官方主页.目前FlexPaper是个开源项目,GPLv3 ...

  7. 将32位MD5摘要串转换为128位二进制字符串

    将32为MD5摘要串转换为128位二进制字符串: /// <summary> /// 将字符串转成二进制 /// </summary> /// <param name=& ...

  8. 为什么重新设计 ASP.NET?

    灵活的跨平台运行时需求 早期 .NET Framework 版本一直作为单一且全面的整体进行安装,每个新版本都包含了新功能和几乎所有早期功能,而鲜有删减,这就不可避免的造成Framework的体积的增 ...

  9. expect入门--自动化linux交互式命令

    很多linux程序比如passwd,ftp,scp,ssh等自身并没有提供一种静默式的执行选项,而是依赖于运行时的终端输入来进行后一步的操作比如更改密码.文件上传.下载等.虽然有些编程语言如java嵌 ...

  10. GitHub上我收藏Java及Android的项目Demo

    接触编程不久但浏览频率最高的还是GitHub毕竟它真的是程序员必不可少的新世界. (2016/9/23更新) 静态更新,很强势你值得拥有 更新资源不需要重新安装APK (2016.9.10更新) ht ...