XSI IPC总论
有三种IPC我们称作XSI IPC,即消息队列、信号量、共享存储器。它们之间有很多相似之处。
XSI IPC源自systemV的IPC功能,由于XSI IPC不使用文件系统的名字空间,而是构造了它们自己的名字空间,为此常常受到批评。(POSIX IPC 使用的是文件系统的名字空间,但我发现很多Linux发行版都不支持POSIX IPC,而systemV IPC却有广泛的支持,故我们只讨论systemV IPC)
|
消息队列 |
信号量 |
共享内存区 |
头文件 |
<sys/msg.h> |
<sys/sem.h> |
<sys/shm.h> |
创建/打开IPC的函数 |
msgget |
semget |
shmget |
控制IPC操作的函数 |
msgctl |
semctl |
shmctl |
IPC操作函数 |
msgsnd msgrcv |
semop |
shmat shmdt |
标识符和键
每个内核中的IPC结构(消息队列、信号量、共享存储段)都用一个非负整数的标识符加以引用。与文件描述符不同,IPC标识符不是小整数。
标识符是IPC对象的内部名。(它是在同种IPC内部循环增长的整型数,即不同种类的IPC对象可能重名,但同种IPC对象不会重名)为使多个合作进程能在同一IPC对象上会合,需要提供一个外部名方案。为此使用键(key),每个IPC对象都与一个键相关联,于是键就用作该对象的外部名。
键的数据类型是key_t,通常在头文件<sys/types.h>中被定义为长整型。
有以下几种方法使客户进程和服务器进程在同一IPC结构上会合:
1、服务器进程可以指定键IPC_PRIVATE创建一个新IPC结构,将返回的标识符存放在文件中,以便客户进程取用。(要读写文件,不好)
2、在一个公用头文件中定义一个客户进程和服务器进程都认可的键。(但此键可能已被占用)
3、客户进程和服务器进程认同一个路径名和项目ID(0—255),接着调用函数ftok将这两个值变换为一个键。然后再方法2中使用此键。(这样可避免键名重复问题)
#include <sys/ipc.h>
key_t ftok (const char*path, int id) ;
ftok就是由一个路径名和项目ID产生一个键。
参数path必须引用一个现存文档。
权限结构
内核给每个IPC对象维护一个信息结构,该结构规定了权限和所有者。其内容跟内核给文件维护的信息类似。
#include <sys/ipc.h>
struct ipc_perm {
uid_t uid ;
gid_t gid ;
uid_t cuid ;
gid_t cgid ;
mode_t mode ;
key_t key ;
……….
} ;
在创建IPC结构时,对所有字段都赋初值。以后,可以调用msgctl、semctl或shmctl修改uid、gid和mode字段。
创建/打开IPC通道
创建/打开一个IPC对象的三个XXXget函数,第一个参数key是类型为key_t的键。返回一个整数标识符。
对于key值,应用程序有两种选择:
1、调用ftok,给它传递pathname和id
2、指定key为IPC_PRIVATE,这将保证会创建一个新的、唯一的IPC对象。
(注意:为访问一个现存IPC对象,绝不能指定IPC_PRIVATE作为键。因为这是一个特殊的键值,它总是用于创建一个新IPC对象)
三个XXXget函数的oflag参数,它指定IPC对象的读写权限位(ipc_perm结构的mode成员),并选择是创建一个新的IPC对象还是访问一个已存在的IPC对象。
对IPC对象来说,IPC_CREAT和IPC_EXCL的组合跟open函数的O_CREAT和O_EXCL的组合类似。
若是创建IPC对象,则必须要指定IPC_CREAT标志。
若是打开IPC对象,则把此标志位置为NULL。