消息对列

消息对列的优势:缓存

1.消息队列是一种先进先出的队列型数据结构,保证先送的货物先到达。服务器

2.消息队列将输出的信息进行了打包处理,这样能够保证以每一个消息为单位进行接收数据结构

3.消息队列还能够对货物进行分类,标记各类类别的货物。函数

消息队列的最佳定义是:内核地址空间中的内部链表。消息能够顺序地发送到队列中,并以几种不一样的方式从队列中获取。固然,每一个消息队列都是由 IPC标识符所惟一标识的。spa

一些命令:查看IPC对象 ipcs  (-q,-s ,-m)指针

     查询IPC对象的所有属性: ipcs     至关于  ipcs -qsm对象

    查询IPC对象的所有属性:  ipcs  -a队列

    删除IPC对象 ipcrm (-q,-s, -a ,-m)  -id进程

每一个IPC对象都有惟一的IPC对象的标识符。不一样类型IPC能够相同。经过标识符在系统内核惟一肯定IPC对象。ip

建立IPC对象,必须制定一个IPC关键字,关键字为32位整数  , KEY描述。

一.管道则只能传送无格式字节流,
     消息队列(也叫报文队列)客服了这些缺点:
     消息队列就是一个消息的链表。
     能够把消息看做一个记录,具备特定的格式。

二.   在某个进程往一个队列写入消息以前,并不须要另外某个进程在该队列上等待消息的到达。这跟管道和FIFO是相反的,对后二者来讲,除非读出者已存在,不然先有写入者是没有意义的。

 

管道和FIFO都是随进程持续的,XSI IPC(消息队列、信号量、共享内存)都是随内核持续的。

 

当一个管道或FIFO的最后一次关闭发生时,仍在该管道或FIFO上的数据将被丢弃。消息队列,除非内核自举或显式删除,不然其一直存在。

 消息队列与命名管道的比较

消息队列跟命名管道有很多的相同之处,经过与命名管道同样,消息队列进行通讯的进程能够是不相关的进程,同时它们都是经过发送和接收的方式来传递数据的。在命名管道中,发送数据用write,接收数据用read,则在消息队列中,发送数据用msgsnd,接收数据用msgrcv。并且它们对每一个数据都有一个最大长度的限制。

 与命名管道相比,消息队列的优点在于

1、消息队列也能够独立于发送和接收进程而存在,从而消除了在同步命名管道的打开和关闭时可能产生的困难。

2、同时经过发送消息还能够避免命名管道的同步和阻塞问题,不须要由进程本身来提供同步方法

3、接收程序能够经过消息类型有选择地接收数据,而不是像命名管道中那样,只能默认地接收。

4. 消息队列提供了消息数据的自动拆分,同时不能接受两次发送的消息。

对于系统中的每一个消息队列,内核维护一个定义在<sys/msg.h>头文件中的信息结构。

 struct msqid_ds {
    struct ipc_perm msg_perm ; 
    struct msg*    msg_first ; //指向队列中的第一个消息
    struct msg*    msg_last ; //指向队列中的最后一个消息
    ……
} ;

建立消息对列:

1.建立一个key,使用函数ftok()

msgget函数

函数msgget,其功能是打开一个现存队列或建立一个新队列。

#include <sys/msg.h>

int  msgget (key_t key,  int oflag) ;

返回值是一个整数标识符,其余三个msg函数就用它来指代该队列。它是基于指定的key产生的,而key既能够是ftok的返回值,也能够是常值IPC_PRIVATE。

若是key为IPC_PRIVATE,则函数建立关键字为0的消息队列。虽然要求关键字惟一,但可建立多个关键字为0的消息队列。

oflag:低9位是访问权限的组合,其余位指定消息队列的建立方式。能够是IPC_CREATE(有则打开,没有则建立)或IPC_CREATE | IPC_EXCL(建立时若是已存在则报错)

msgsnd函数

使用msgsnd打开一个消息队列后,咱们使用msgsnd往其上放置一个消息。

#include <sys/msg.h>

int  msgsnd (int msqid,  const void *ptr,  size_t length,  int flag) ;

1.   msqid是由msgget返回的标识符。

2.   ptr是一个结构指针,该结构具备以下模板(咱们须要按这个模板本身定义结构体,只要结构的第一个成员维持long型不变)

struct mymesg {
    long  mtype ;     //消息类型(大于0)
    char  mtext[512] ;  //消息数据
} ;//结构体的名字和其中变量名都由咱们本身肯定,咱们只要按照这个模板定义便可。

消息数据mtext中,任何形式的数据都是容许的,不管是二进制数据仍是文本,内核根本不解释消息数据的内容。(咱们能够在消息的数据部分 再分割一部分 根据须要定义本身的通讯协议)

3. 参数length指定待发送消息数据部分的长度。注意是消息的长度,而不是整个结构体的长度,也就是说msg_sz是不包括长整型消息类型成员变量的长度。必须大于0

4. 参数flag的值能够指定为IPC_NOWAIT。这相似于文件IO的非阻塞IO标志。若消息队列已满,则指定IPC_NOWAIT使得msgsnd当即出错返回EAGAIN。

若是没有指定IPC_NOWAIT,则进程阻塞直到下述状况出现为止:①有空间能够容纳要发送的消息 ②从系统中删除了此队列(返回EIDRM“标识符被删除”)③捕捉到一个信号,并从信号处理程序返回(返回EINTR)

用于控制当前消息队列满或队列消息到达系统范围的限制时将要发生的事情。???

调用成功,消息数据的一分份副本将被放到消息队列中,并返回0,失败时返回-1.

阻塞的两种状况:

消息队列满,要发送的数据 + 消息队列已使用的字节数,超过消息队列可容纳的最大字节数。

消息总数满:系统中全部消息对列记载的消息总数已经超过系统的上限值。

error的值:消息对列被删除,error置为EIDRM

      发送消息过程当中接到信号,消息发送中断,,error置为EINTR

      设置为非阻塞,当消息队列满时,error置为EAGAIN

msgrcv函数

使用msgrcv函数从某个消息队列中读出一个消息。

#include <sys/msg.h>

ssize_t  msgrcv (int msqid,  void* ptr,  size_t length,  long type,  int flag) ;

参数ptr指定所接收消息的存放位置。参数length指定了数据部分大小(只想要多长的数据)

参数length,包括消息类型的部分。

参数type指定但愿从队列中读出什么样的消息。

type == 0 返回队列中的第一个消息

type > 0  返回队列中消息类型为type的第一个消息

type < 0  返回队列中消息类型值小于或等于type绝对值的消息,若是这种消息有若干个。则取类型值最小的消息。

(若是一个消息队列由多个客户进程和一个服务器进程使用,那么type字段能够用来包含客户进程的进程ID)

参数flag能够指定为IPC_NOWAIT,使操做不阻塞。

      MSG_NOERROR , 截断读取消息,当接收到的消息长度大于缓冲区长度时,截断消息。只接收length长,剩余的下次接收。

              没有设置MSG_NOERROR ,发生上述状况则error置为E2BIG

调用成功时,该函数返回放到接收缓存区中的字节数,消息被复制到由msg_ptr指向的用户分配的缓存区中,而后删除消息队列中的对应消息。失败时返回-1

msgctl函数

msgctl函数提供在一个消息队列上的各类控制操做。

查询消息队列数据结构,改变消息队列访问权限,改变消息队列属主信息和删除消息队列

#include <sys/msg.h>

int  msgctl (int msqid,  in cmd,  struct msqid_ds * buff) ;

参数cmd说明对由msqid指定的队列要执行的命令:

IPC_STAT :取此队列的msqid_ds结构,并将它存放在buf指向的结构中。

IPC_SET  :按由buf指向结构中的值,设置与此队列相关结构中的字段。

IPC_RMID:从系统中删除该消息队列以及仍在该队列中的全部数据。

(这三条命令也可用于信号量和共享存储)

 常见应用模型:

1.单一消息对列完成对等进程间的双向通讯模型

2.双消息队列完成对等进程间的双向通讯

3.单一消息队列完成客户-服务器件的双向通讯

4.双消息队列完成客户-服务器进程间的双向通讯

相关文章
相关标签/搜索