您的位置:首页 > 其它

System V IPC 初识以及简单介绍

2015-07-21 17:22 218 查看
这里将会讨论对于System V IPC的初步认识

以下三种类型的IPC合称为System V IPC:

System V 消息队列

System V 信号量

System V 共享内存区




key_t键 和 ftok函数

以上谈到的三种IPC都使用key_t作为他们的名字. key_t在<sys/types.h>头文件中被定义为一个整数, 通常至少为32位

函数ftok把一个[已存在的路径名,pathname]和一个[整数标识符,id]转换称一个key_t值, 称为IPC键

key_t ftok(const char *pathname, int proj_id);
此函数假定对于使用System V IPC的某个给定应用来说, 客户和服务器同意使用对该应用有一定意义的pathname. 它可以是服务器守护程序的路径名, 服务器使用的某个公共数据文件的路径名或者系统上的某个其他路径名. 如果客户和服务器之间只需要单个IPC通道, 那么可以使用譬如说值为1的id. 如果需要多个IPC通道, 譬如从客户到服务器, 从服务器到客户两个通道, 那么作为例子, 一个可以值为1的id, 另一个可以值为2的id. 客户和服务器一旦在pathname
和 id达成一致, 双方就能调用ftok将这两者转换称同一个IPC键

ftok的典型实现调用stat函数, 然后组合以下三个值:

1, pathname所在文件系统的信息(st_dev)

2 该文件在文件系统内的索引节点号(st_ino)

3 id的低序8位

通常用这三个值组成32位的键. 可以发现,并不能保证两个不同的路径名与同一个id的组合产生不同的键

如果pathname不存在, 或者对于调用进程不可访问, 返回-1 (值得注意的是, 路径名不要指定为那种在服务器存活期间被反复删除创建的那种, 因为每次创建系统给其的st_ino都可能不同,于是对于下一个调用ftok的调用者来说, 返回得到的key也可能会不同)

如果向看清楚ftok产生的键, 那么以下程序可以有所帮助:

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>

//Here we watch how the key was created by ftok
//the key consists of three parts of these three values

int main(int ac, char *av[])
{
struct stat sa;

if(ac != 2)
exit(-1);;

if(stat(av[1], &sa) == -1)
exit(-1);

printf("st_dev : %lx, st_ino : %lx, key : %lx \n", sa.st_dev, sa.st_ino, ftok(av[1], 0x57));
return 0;
}


$ ./f /home/Ben/xxx
st_dev : 807, st_ino : 141b76, key : 57071b76

$ ./f /home/Ben/xxxx
st_dev : 807, st_ino : 14156e, key : 5707156e

$ ./f /xxxxx
st_dev : 806, st_ino : 200001, key : 57060001


ipc_perm结构

这是内核为每个IPC对象维护的一个信息结构, 其内容跟内核给文件维护的信息类似

/* Data structure used to pass permission information to IPC operations.  */
struct ipc_perm
{
__key_t __key;                       /* Key.  */
__uid_t uid;                         /* Owner's user ID.  */
__gid_t gid;                         /* Owner's group ID.  */
__uid_t cuid;                        /* Creator's user ID.  */
__gid_t cgid;                        /* Creator's group ID.  */
unsigned short int mode;             /* Read/write permission.  */
unsigned short int __pad1;
unsigned short int __seq;            /* Sequence number.  */
unsigned short int __pad2;
unsigned long int __unused1;
unsigned long int __unused2;
};
接下来为解析其中的部分成员

创建与打开IPC通道

创建或打开一个IPC对象的三个 XXXget 函数的第一个参数是key, 即为IPC键

对于key的值,应用程序有两种选择:、

(1) 调用ftok, 给它传递pathname和id

(2) 指定key为IPC_PRIVATE,这将保证为创建一个新的, 唯一的IPC对象



每个 XXXget 函数中都有一个flag参数, 它用于指定IPC对象的读写权限位, 也即ipc_oerm中的 mode

指定key为IPC_PRIVATE能保证创建一个唯一的IPC对象

设置flag为IPC_CREAT,没有IPC_EXCL时,如果指定IPC不存在, 就创建,存在就返回该对象

设置flag为IPC_CREAT和IPC_EXCL时,如果指定IPC不存在, 就创建,存在就返回错误EEXIST

IPC权限

每当创建一个新的IPC对象时, 以下信息就会被保存在opc_perm中

(1) flag中的某些位初始化ipc_perm中的mode

(2) cuid和cgid分别设置调用进程的有效用户ID和有效组ID,合称创建者ID

(3) uid和gid也设置为调用进程的有效用户ID和有效组ID,合称属主ID

尽管一个进程可以通过调用相应的XXXctl函数, 修改属主ID, 创建者ID却从不改变

相比较Posix IPC, Posix不允许一个IPC对象的创建者改变对象的属主,没有类似修改的操作. 然而如果Posix IPC名字存储在文件系统中, 超级用户可以可以chown改变其属主

每当有进程访问某IPC时候,该IPC在被打开时候执行一次检查, 以后每次使用该对象时执行一次检查

具体来说:

(1) 每当有进程使用XXXget函数访问某个已存在的IPC对象通道时,IPC就执行第一次检查, 查看调用者的flag参数有没有指定不存在该对象ipc_perm结构mode成员中的任何访问位. 比如说服务器把它的消息队列的mode设置成其他用户只能读的权限, 那么当属于其他的某进程在调用XXXget函数中的flag中指定了写位时,那么该函数将返回一个错误

但是, 其实XXXget对权限的检验并没有什么用处,如果创建者把所有写权限都关闭了, 然而调用者指定了写位,那么就会返回错误; 但是如果调用者此时简单的指定XXXget的flag为0, 那么就调用成功了

(2) 每次对IPC操作都会被执行一次权限检查. 每当有一个进程试图往消息队列写数据时, 比如使用msgsnd函数,函数将会按下面顺序执行权限检测:

(1) 超级用户总是允许

(2) 当前进程的有效用户ID等于该IPC的uid或cuid值, 且相应的位被设置,那么就可以 (比如写函数,检测写位是否被设置; 读函数则检测读位)

(3) 当前进程有效组ID

(4) 检测‘其他用户’访问位在ipc_perm中的mode对应是否打开

标志符的重用

ipc_perm中有一个 seq 的变量, 它是槽位使用情况序列号, 它也是XXXget函数的返回值

该变量是一个由内核为系统中每一个潜在的IPC队列维护的计数器, 每当删除一个IPC, 内核就递增相应的槽位号, 溢出则循环回0

该计数器的存在有两个原因.

首先, 与每个进程的文件描述符相比较, 文件描述符的值在没有亲缘关系的进程中是没有意义的, 因为文件描述符是针对单进程的,是进程特定值, 他们都是些小整数. 然而System V IPC却是系统范围的, 不限制与单个进程. 如果两个无亲缘关系的进程使用单个消息队列, 那么由msgget函数返回的消息队列的标志符在双方进程中必须是同一个整数, 如此双方才能访问同一个消息队列

标志符不是小整数是因为安全原因(UNP2, Ch3.6). 观察msgctl, msgsnd等函数的第一个参数即是此标志符.若使用小整数,且此时某个危险进程试图从某个消息队列读取消息, 办法是尝试不同的小整数,那么找到有效的标志符的可能性比较大. 因此IPC中的标志符范围扩大到所有整数,不仅仅是小整数

其次, 使用标志符的原因是避免短时间内重用标志符号,有助于确保过早终止的服务器重新启动不会重用标志符

由于System V IPC不是以文件系统中的路径名标志的,所以使用ls,rm等无法看到它

不过使用ipcs 和 ipcrm 命令可以对IPC进行操作

ipcs输出System V IPC特性的各种消息; ipcrm用于删除IPC对象
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: