发信人: tcpip (俺的昵称改了), 信区: cnunix
标  题: 本地进程间通信第四讲:消息队列(一)
发信站: 哈工大紫丁香 (Sun Sep 26 16:47:55 1999), 转信

发信人: cpu (奔腾的心), 信区: Solaris
发信站: 华南网木棉站 (Tue Oct  6 10:17:49 1998), 转信

消息队列是systemV上头ipc的东东。由于它不是流通信,所以容易被忽视。有一条
命令叫ipcs,就是ipc state的意思,可以帮你查看目前ipc资源的状态:有多少消
息队列,信号灯,共享内存,这些全是systemV的东西。比如:

(smc)/usr/chinanet/bin% ipcs
IPC status from <running system> as of Mon Oct  5 15:10:24 1998
T     ID     KEY        MODE       OWNER    GROUP
Message Queues:
q    100 0x0000169d -Rrw-rw---- chinanet    other
q     51 0x000011d7 -Rrw-rw---- chinanet    other
Shared Memory:
Semaphore facility not in system.

smc这台机器里面有两个消息队列,即Message Queues下面那两行,没有共享内存
和信号灯在利用。对于大多数系统,几乎没有进程在利用systemV的ipc。比如:

(gnet-server)/export/home/digger% ipcs
IPC status from <running system> as of Mon Oct  5 03:06:06 1998
Message Queue facility not in system.
Shared Memory:
Semaphores:

没法子,更多的程序员喜欢利用流的方式来进行本地ipc,比如unix域的socket和
管道等等,socket或者管道的打开id和普通文件号没什么区别,可以象读写普通
文件一样来处理它们,可以很容易的和其它类型的文件id一起整和到select调用
的圈子里。。。而这恰恰是systemV ipc的缺陷:systemV ipc的打开id也是整形,
但是和普通文件号不“兼容”,不能对该id进行read,write,一定要特殊的调用,
更糟糕的是,system ipc资源状态的改变需要你自己探询,比如消息队列里有你
所需要的消息了,操作系统不会发信号来通知你,你也不可能select到消息队列
里头已经有东西可读,SIGH。。。systemV ipc的东西真的这么差劲么?偶的感觉
是这样的,但是systemV ipc也有可取的地方,比如消息队列,在一对多的通信环
境里,可以只采用一个队列。

说了这么多systemV ipc的缺点,不等于偶在这一系列中就cancel了它们。这一节
讲一下systemV消息队列的概念和相关调用。

消息队列实际上是个由消息块组成的链表,不是完全先进先出的队列。消息队列的
创建由系统调用msgget完成。

各个进入消息队列的消息块会被依次挂接到链表尾,但是出队列的消息块不是由链
表头开始的,而是根据用户的要求有选择地从链表中摘除,这个选择的关键就在于
消息块的结构中有个消息类型分量,这样接收消息的时候可以指定所需要消息的类
型。

消息块的结构可以由用户任意指定,但是第一个分量必须为大于0的long类型,同时
整个消息块的长度最大为64K。比如:

     struct mymessage {
                      long msg_type;
                      char msg_string[40];
                      } ;

链表的结构属于内核范畴,泥有兴趣可以自己看看。把消息块挂接到链表尾就是发
消息操作,把所需要的消息从链表中摘除就是收消息操作,这些都有相关的系统调
用来完成。收发消息的系统调用分别为msgsnd和msgrcv。

很多系统中规定一个消息队列中最多容纳40个消息。当消息队列满的时候发消息就
会阻塞或者失败;同理消息队列空或者队列中没有所需要类型消息的时候收消息也
会阻塞或者失败。

(1)创建消息队列或者得到已存在消息队列的id:

     #include <sys/types.h>
     #include <sys/ipc.h>
     #include <sys/msg.h>

     int msgget(key_t key, int msgflg);

key_t实际上就是int,定义在sys/types.h里面。key是这个消息队列的键值,相互
作的进程用同一个key来msgget同一个消息队列就可以用该消息队列来通信了。

msgflg为以下几个选项的或:
1. access_mode: 同creat调用,但只有读写标志有效,比如0600,只有进程owner
与创建消息队列进程相同的进程才有权限读写该消息队列。
2. IPC_CREAT: 如果消息队列不存在就创建。
3. IPC_EXCL: 如果消息队列存在,且msgflg包含IPC_CREAT选项,msgget出错。

调用成功返回消息队列的id。

(2)发送消息

     #include <sys/types.h>
     #include <sys/ipc.h>
     #include <sys/msg.h>

     int msgsnd(int msqid, const void *msgp, size_t msgsz,
          int msgflg);

msqid是msgget返回的消息队列id。

msgp是消息缓冲区指针,消息的结构可以自己按需要指定,但是第一个分量一定是
大于0的long类型,比如上面提到的mymessage结构。

msgsz是发送消息的长度。对上述结构可以为sizeof(struct mymessage)。

msgflag一般为0,如果为IPC_NOWAIT,那么指定为非阻塞方式,如果消息队列已满
发不了消息或者没有所需类型消息的消息可读,msgsnd和msgrcv马上返回-1。

(3)接收消息

     #include <sys/types.h>
     #include <sys/ipc.h>
     #include <sys/msg.h>

     int msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
          int msgflg);

前四个输入参数的意义同msgsnd。

msgtyp指定msgrcv所要接收的消息类型,即任意消息结构的第一个long分量,比如
struct mymessage的msg_type分量。msgrcv指定的msgtyp有以下意义:
     
     如果msgtyp == 0,那么接收消息队列中的第一个消息。
     如果msgtyp > 0,那么接收消息队列中第一个消息类型等于msgtyp的消息。
     如果msgtyp < 0,那么接受消息队列中第一个消息类型不大于msgtyp绝对值的
     消息。

msgtyp是消息队列编程的关键,具体怎么应用下节续讲。
--

        ******************************************************
                
               青岛啤酒,可能是世界上最好的啤酒 。。。 。。。

        ******************************************************
※ 修改:.trueip 于 Sep 26 15:48:30 修改本文.[FROM: dns.mtlab.hit.ed]
--
※ 转寄:.华南网木棉站 bbs.gznet.edu.cn.[FROM: dns.mtlab.hit.ed]

--
☆ 来源:.哈工大紫丁香 bbs.hit.edu.cn.[FROM: trueip.bbs@melon.gzn]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:3.868毫秒