Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1736501
  • 博文数量: 438
  • 博客积分: 9799
  • 博客等级: 中将
  • 技术积分: 6092
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-25 17:25
文章分类

全部博文(438)

文章存档

2019年(1)

2013年(8)

2012年(429)

分类: 系统运维

2012-04-02 16:59:36

三种我们称为XSI IPC的IPC类型--消息队列、信号量、和共享内存--有许多相似点。在本节,我们覆盖这些相似的特性;在之后的几节, 我们看下这三个IPC类型的每个所相关的函数。


XSI IPC函数紧密地基于系统V IPC函数。这三种类型的IPC起源于上世纪70年代,在一个UNIX内部AT&T版本的UNIX系统里,称为“Columbus UNIX”。这些IPC特性稍后被加入到系统V里。它们通常因为创建它们自己的命名空间而不是文件系统而被批评。


回想15.1节,消息队列、信号量、和共享内存被作为SUS里的XSI扩展定义。


15.6.1 标识符和关键字(Identifiers and Keys)


每 个IPC结构体(消息队列、信号量、或共享内存段)在内核里被一个非负整型标识符引用。为了向一个消息队列发送或从它那里得到一个消息,我们所有需要知道 的只是队列的标识符。不像文件描述符,IPC描述符不是小整数。事实上,当一个给定的IPC结构体被创建然后被删除时,和那个结构体相关的标识符持续增 加,直到达到了一个整型的最大正值,然后回到0。


标识符是一个IPC对象的内部名字。合作进程需要一个外部命名机制来集结地使用相同的IPC对象。为了这个目的,一个IPC对象被关联到一个关键字,它作为一个外部名字。


每 当一个IPC结构体正被创建时(通过调用msgget、semget、或shmget),一个关键字必须被指定。这个关键字的数据类型是原始系统数据类型 key_t,它经常被定义为一个长整型,在头文件里。这个关键字被内核转换为一人标识符。


一个客户端和服务器有多种方式集结在相同的IPC结构体。


1、 服务器可以创建一个IPC结构体,通过指定一个IPC_PRIVATE的关键字,并把返回的标识符存储在某地(比如一个文件),以便客户得到。关键字 IPC_PRIVATE保证了服务器创建了一个新的IPC结构体。这个技术的缺点是文件系统操作被服务器需要,以在一个文件写入整型标识符,以便让客户端 稍后得到这个标识符。IPC_PREVIATE关键字也在父子关系里使用。父进程创建一个新的IPC结构体,指定IPC_PRIVATE,最后的标识符在 fork之后然后对子进程可用。子进程可以传递标识符给一个新程序,作为某个exec函数的一个参数。


2、客户端和服务器可以对一个关键字 达成共识,例如通过以一个通用头来定义关键字。服务器然后创建一个新的指定这个关键字的IPC结构体。这种方式的问题是关键字可能已经被关联到一个IPC 结构体上,在这种情况下get函数(msgget、semget、或shmget)返回一个错误。服务器必须处理这个错误,删除已存在的IPC结构体,并 再次尝试创建它。


3、客户端和服务器可以对一个路径名和工程ID上达成共识(工程ID是0到255的一个字符值),并调用函数ftok来把这两个值转换到一个关键字里。这个关键字然后在步骤2里使用。ftok提供的唯一服务是从一个路径名和工程ID产生一个关键字的一个方法。



  1. #include <sys/ipc.h>
  2. key_t ftok(const char *path, int id);

  3. 成功返回关键字,失败返回(key_t)-1。


path参数必须指向一个已有的文件。在产生关键字时只有id的低8位被使用。


被 ftok创建的关键字通常由对应于给定路径名的stat结构体(4.2节)里的st_dev和st_ino域的部分组成,并把它们和工作ID结合。如果两 个路径名指向两个不同的文件,那么ftok通常为两个路径名返回两个不同的关键字。然而,因为i-node号和关键字经常都被存储在长整型里,所以创建一 个关键字里可能有信息丢失。这意味着两个指向不同文件的不同的路径名可以产生相同的关键字,如果相同的工程ID被使用。


这三个get函数 (msgget、semget、和shmget)都有两个相似的参数:一个关键字和一个整型标志。一个新的IPC结构体被创建(通常被一个服务器),如果 关键字是IPC_PRIVATE,或者当前没有和特定类型的一个IPC结构体相关联且标志的IPC_CREAT位被指定。为了引用一个已有的队列(通常由 一个客户端完成),关键字必须和当队列被创建时所指定的关键字相同,而且IPC_CREAT必须不能被指定。


注意决不可能指定 IPC_PRIVATE来指定一个已有的队列,因为这个特殊的关键字值总是创建一个新的队列。为了引用一个用IPC_PRIVATE的关键字创建的已存在 的队列,我们必须知道相关联的标识符,然后在其它IPC调用里使用那个标识符(比如msgsnd和msgrcv),绕开get函数。


如果我 们想创建一个新的IPC结构体,以确保我们不会用相同的标识符引用到一个已经存在的,那么我们必须同时设置IPC_CREAT和IPC_EXCL位来指定 一个标志。这样做导致一个EEXIST的错误返回,如果IPC结构体已经存在。(这和指定O_CREAT和O_EXCL标志的open相似。)


15.6.2 权限结构体(Permission Structure)


XSI IPC把一个ipc_perm结构体关联到每个IPC结构体里。这个结构体定义了权限和属主,并至少包含以下的成员:
struct ipc_perm {
  uid_t uid;  /* owner's effective user id */
  gid_t gid;  /* owner's effective group id */
  uid_t cuid;  /* creator's effective user id */
  gid_t cgid;  /* creator's effective group id */
  mode_t mode;  /* access modes */
  ...
};


每个实现包含补充的成员。在你的系统上看来得到完整的定义。


所 有的域在IPC结构体被创建时被初始化。在稍后某个时刻,我们可以修改uid、gid和mode域,通常调用msgctl、semctl或shmctl。 为了改变这些值,调用进程必须是IPC结构体的创建者或者超级用户。改变这些域和为一个文件调用chown或chmod相似。


mode域里的值和我们在第4章看到的值相似,但是没有对应的任何IPC结构体的执行权限。同样,消息队列和共享内存使用术语读和写,但是信号量使用术语读和改变(alter)。下表展示了每种形式的IPC的6个权限。


XSI IPC权限
权限
用户读0400
用户写(改变)0200
组读0040
组写(改变)0020
其他人读0004
其他人写(改变)0002

一些实现定义符号常量来表示每个权限,尽管如此,这些常量不被SUS标准化。

15.6.3 配置限量(Configuratoin Limits)

所有三种形式的XSI IPC都有我们可能碰到的内置的限量。这些限量里多数可以通过重新配置内核来改变。我们在描述这三种形式的IPC中的每个时描述这些限量。


每个平台提供它自己的方式来报告和修改一个特定的限量。FreeBSD、Linux和Mac提供sysctl命令来查看和修改内核配置参数。Solaris上,对内核配置参数的改变由修改文件/etc/system并重启来完成。


在Linux上,你可以显示IPC相关的限量,通过运行ipcs -l。在FreeBSD上,等价的命令是ipcs -T。在Solaris上,你可以发现可调的参数,通过运行sysdef -i。


15.6.4 优点和缺点(Advantages and Disadvantages)

XSI IPC的一个基本的问题是IPC结构体是系统范围的且没有一个引用计数。例如,如果我们创建一个消息列队,在上面放置一些消息,然后终止,那么消息队列和 它的内容不会被删除。它们停留在系统里,直到被确切地读或删除,通过一些进程调用msgrcv或msgctl、或者执行ipcrm命令、或者系统重启。把 这个和管道比较,后者在最后一个引用它的进程终止时会被完全删除。对于FIFO,尽管名字保存在文件系统,直到显式地删除,但是任何在FIFO里的数据在 最后一个引用这个FIFO的进程终止里会被删除。


XSI IPC的另一个问题是这些IPC结构体不能在文件系统里通过名字知道。我们不能访问它们或修改它们的属性,使用第3、4章的函数。几乎有一打新的系统调用 (msgget、semop、shmat等)被加入到内核来支持这些IPC对象。我们不能用ls命令看到这些IPC对象,不能用rm命令删除它们,也不能 用chmod命令来改变它们的权限。相反,两个新命令--ipcs和ipcrm--被加入。


因为这些形式的IPC不使用文件描述符,所以我 们不能在它们上使用复用I/O函数(select和poll)。这导致同时使用多个这样的IPC结构体或通过文件或设备I/O来使用这些IPC结构体更加 困难。例如,我们不能让一个服务器等待一个被放置到两个消息队列中的某个的消息,而不通过一些忙等待形式的循环。


一个使用系统V IPC建立的一个事务处理系统的总览被Andrade、Carges和Kovach[1989]给出。他们声明系统V IPC使用的命名空间(标识符)是一个优点,不是一个如我们之前所说的问题,因为使用标识符允许一个进程使用单个函数调用(msgsnd)来向一个消息队 列发送消息,而一些形式的IPC通常需要一个open、write和close。这个争论是不恰当的。客户端仍然需要得到服务器的队列的标识符,以某种方 式,来避免使用一个关键字和调用msgget。分配给一个特定队列的标识符取决于当队列被创建时有多少其它消息队列,以及内核里分配给新队列的表自从内核 重启后被使用了多少次。这是一个动态的值,不能被猜测或存储在一个头文件里。如我们在15.6.1节里提到的,一个服务至少要把分配的队列标识符写到一个 文件以便客户来读。


另一个这些作者为消息队列所列出的优点是它们很可靠、流控制的、面向记录的、以及可以以不是先进先出的其它方式被处理。 正如我们在14.4节里看到的,STREAMS机制也处理所有这些属性,尽管需要在发送数据给一个流之前需要一个open,在我们完成时需要一个 close。下表比较了这些各种形式的IPC的一些特性。


各种形式的IPC的特性的比较
IPC类型无连接的?可靠的?流控制?记录?消息类型或优先级?
消息队列
STREAMS
UNIX域流套接字
UNIX哉数据报套接字
FIFO(非STREAMS)


(我 们在16章描述流和数据报套接字。在17.3节描述UNIX域套接字。)“无连接”的意思是不必先调用某种形式的打开函数来发送一个消息的能力。如之前描 述的,我们不把消息队列视为无连接的,因为需要一些技术来得到一个队列的标识符。因为所有这些形式的IPC被限制为单个主机,所以所有的都是可靠的。当消 息通过一个网络发送时,消息被丢失是有可能的。“流控制”表示发送者被催眠,如果系统资源短缺(buffer)或接收者没有接受任何更多的消息。当流控制 条件消退时,发送者应该自动被唤醒。


一个我们没有在上表展示的特性是IPC设施是否可以为每个客户自动创建到服务器的唯一的连接。我们将在17章看到STREAMS和UNIX流套接字提供了这种能力。


下面三节深入描述了这三种形式的XSI IPC的每一个。

阅读(1092) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~