设为首页 加入收藏

TOP

深入理解进程间通信之消息队列(一)
2015-07-20 12:52:43 来源: 作者: 【 】 浏览:56
Tags:深入 理解 进程 通信 消息 队列

消息队列是消息的链接表,包括Posix消息队列system V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。消息队列是随内核持续的。


IPC持续概念


消息队列的基本概念


  系统V消息队列是随内核持续的,只有在内核重启或者显示删除一个消息队列时,该消息队列才会真正被删除。因此系统中记录消息队列的数据结构(struct ipc_ids msg_ids)位于内核中,系统中的所有消息队列都可以在结构msg_ids中找到访问入口。


  消息队列就是一个消息的链表。每个消息队列都有一个队列头,用结构struct msg_queue来描述。队列头中包含了该消息队列的大量信息,包括消息队列键值、用户ID、组ID、消息队列中消息数目等等,甚至记录了最近对消息队列读写进程的ID。读者可以访问这些信息,也可以设置其中的某些信息。


结构msg_queue用来描述消息队列头,存在于系统空间:


?struct msg_queue {
? ? struct kern_ipc_perm q_perm;
? ? time_t q_stime;? ? ? ? /* last msgsnd time */
? ? time_t q_rtime;? ? ? ? /* last msgrcv time */
? ? time_t q_ctime;? ? ? ? /* last change time */
? ? unsigned long q_cbytes;? ? /* current number of bytes on queue */
? ? unsigned long q_qnum;? ? ? /* number of messages in queue */
? ? unsigned long q_qbytes;? ? /* max number of bytes on queue */
? ? pid_t q_lspid;? ? ? ? ? /* pid of last msgsnd */
? ? pid_t q_lrpid;? ? ? ? ? /* last receive pid */
? ? struct list_head q_messages;
? ? struct list_head q_receivers;
? ? struct list_head q_senders;
};


结构msqid_ds用来设置或返回消息队列的信息,存在于用户空间:


struct msqid_ds {
? ? struct ipc_perm msg_perm;
? ? struct msg *msg_first;? ? ? /* first message on queue,unused? */
? ? struct msg *msg_last;? ? ? /* last message in queue,unused */
? ? __kernel_time_t msg_stime;? /* last msgsnd time */
? ? __kernel_time_t msg_rtime;? /* last msgrcv time */
? ? __kernel_time_t msg_ctime;? /* last change time */
? ? unsigned long? msg_lcbytes; /* Reuse junk fields for 32 bit */
? ? unsigned long? msg_lqbytes; /* ditto */
? ? unsigned short msg_cbytes;? /* current number of bytes on queue */
? ? unsigned short msg_qnum;? ? /* number of messages in queue */
? ? unsigned short msg_qbytes;? /* max number of bytes on queue */
? ? __kernel_ipc_pid_t msg_lspid;? /* pid of last msgsnd */
? ? __kernel_ipc_pid_t msg_lrpid;? /* last receive pid */
};


下图说明了内核与消息队列是怎样建立起联系的:


其中:struct ipc_ids msg_ids是内核中记录消息队列的全局数据结构;struct msg_queue是每个消息队列的队列头。



从上图可以看出,全局数据结构 struct ipc_ids msg_ids 可以访问到每个消息队列头的第一个成员:struct kern_ipc_perm;而每个struct kern_ipc_perm能够与具体的消息队列对应起来是因为在该结构中,有一个key_t类型成员key,而key则唯一确定一个消息队列。 kern_ipc_perm结构如下:


struct kern_ipc_perm{? //内核中记录消息队列的全局数据结构msg_ids能够访问到该结构;
key_t? key;? ? //该键值则唯一对应一个消息队列
uid_t? uid;
gid_t? gid;
uid_t? cuid;
gid_t? cgid;
mode_t? mode;
unsigned long seq;
}


1、 打开或创建消息队列


  消息队列的内核持续性要求每个消息队列都在系统范围内对应唯一的键值,所以,要获得一个消息队列的描述字,只需提供该消息队列的键值即可;


  注:消息队列描述字是由在系统范围内唯一的键值生成的,而键值可以看作对应系统内的一条路经。


2、 读写操作


  消息读写操作非常简单,对开发人员来说,每个消息都类似如下的数据结构:


3、 获得或设置消息队列属性:


  消息队列的信息基本上都保存在消息队列头中,因此,可以分配一个类似于消息队列头的结构,来返回消息队列的属性;同样可以设置该数据结构。


?


?


1.文件名到键值


2. Linux为操作系统V进程间通信的三种方式(消息队列、信号灯、共享内存区)提供了一个统一的用户界面:


第一个参数指明对IPC对象的操作方式,对消息队列而言共有四种操作:MSGSND、MSGRCV、MSGGET以及MSGCTL,分别代表向消息队列发送消息、从消息队列读取消息、打开或创建消息队列、控制消息队列;first参数代表唯一的IPC对象;下面将介绍四种操作。


注:本人不主张采用系统调用ipc(),而更倾向于采用系统V或者POSIX进程间通信API。原因如下:


3.系统V消息队列API


  系统V消息队列API共有四个,使用时需要包括几个头文件:


1int msgget(key_t key, int msgflg)


参数key是一个键值,由ftok获得;msgflg参数是一些标志位。该调用返回与健值key相对应的消息队列描述字。


在以下两种情况下,该调用将创建一个新的消息队列:


参数msgflg可以为以下:IPC_CREAT、IPC_EXCL、IPC_NOWAIT或三者的或结果。


调用??回:成功返回消息队列描述字,否则返回-1。


注:参数key设置成常数IPC_PRIVATE并不意味着其他进程不能访问该消息队列,只意味着即将创建新的消息队列。


2int msgrcv(int msgid, struct msgbuf *msgp, int msgsz, long msgtyp, int msgflg);


该系统调用从msgid代表的消息队列中读取一个消息,并把消息存储在msgp指向的msgbuf结构中。


msqid为消息队列描述字;消息返回后存储在msgp指向的地址,msgsz指定msgbuf的mtext成员的长度(即消息内容的长度),msgtyp为请求读取的消息类型;读消息标志msgflg可以为以下几个常值的

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇jQuery删除数组中重复元素 下一篇深入理解进程间通信之信号

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: