消息队列以链表的方式将消息存储于内核中,调用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. Unity烂笔头1-自定义INSPECTOR属性窗口节点项

    1.添加输入框和标签 LevelScript: using UnityEngine; using System.Collections; public class LevelScript : Mono ...

  2. 通过js获取前台数据向一般处理程序传递Json数据,并解析Json数据,将前台传来的Json数据写入数据库表中

    摘自:http://blog.csdn.net/mazhaojuan/article/details/8592015 通过js获取前台数据向一般处理程序传递Json数据,并解析Json数据,将前台传来 ...

  3. 关于迭代器中IEnumerable与IEnumerator的区别

    首先是IEnumerable与IEnumerator的定义: 1.IEnumerable接口允许使用foreach循环,包含GetEnumerator()方法,可以迭代集合中的项. 2.IEnumer ...

  4. Mongodb 语法,update,insert,delete,find

    ---恢复内容开始--- db.Users.update({OrganizationCode:"Global"},{$set:{OrganizationCode:"Fre ...

  5. 【C#进阶系列】08 方法

    实例构造与引用类型 之前的章节其实已经写过了引用类型的构造过程: 首先当然是,在堆中,为引用类型的实例对象分配内存,然后初始化对象的附加字段(即类型对象指针和同步块索引). 这个时候为对象分配的内存都 ...

  6. 【jQuery基础学习】05 jQuery与Ajax以及序列化

    好吧,这章不像上章那么水了,总是炒剩饭也不好. 关于AJAX 所谓Ajax,全名Asynchronous JavaScript and XML.(也就异步的JS和XML) 简单点来讲就是不刷新页面来发 ...

  7. 与众不同 windows phone (36) - 8.0 新的瓷贴: FlipTile, CycleTile, IconicTile

    [源码下载] 与众不同 windows phone (36) - 8.0 新的瓷贴: FlipTile, CycleTile, IconicTile 作者:webabcd 介绍与众不同 windows ...

  8. 解决Cannot change version of project facet Dynamic Web M

    dynamic web module 版本之间的区别: Servlet 3.0 December 2009 JavaEE 6, JavaSE 6 Pluggability, Ease of devel ...

  9. Sass学习之路(1)——Sass简介

    Sass是CSS的一种预处理器语言,类似的语言还有Less,Stylus等. 那么什么是CSS预处理器? CSS 预处理器定义了一种新的语言,其基本思想是,用一种专门的编程语言,为 CSS 增加了一些 ...

  10. DevExpress GridControl使用方法总结

    一.如何解决单击记录整行选中的问题 View->OptionsBehavior->EditorShowMode 设置为:Click 二.如何新增一条记录 (1).gridView.AddN ...