一、System V IPC基础
System V提供的IPC机制主要有:消息队列、信号量和共享内存 3种机制。和文件一样,IPC在使用前必须先创建,每种IPC都有特定的生产者、所有者、和访问权限。使用ipcs命令可以查看当前系统正在使用的IPC工具,可以作为调试程序的一个重要手段:
由上图可以看出,一个IPC工具至少包含key值、ID值、拥有者、权限和使用的大小等关键信息。如果需要手工删除某个IPC机制,可使用ipcrm命令。
二、key值和ID值
Linux系统为每个IPC机制都分配了唯一的ID,所有针对IPC机制的操作都使用该ID值。通信双方都需要通过某个方法来获取ID值。为了解决这一问题,IPC在实现时约定使用key值做为参数创建,如果在创建时使用相同的key值将得到同一个IPC对象的ID(即一方创建ID,另一方仅仅是获取ID),这样就保证了双方可以获取用于床底数据的IPC机制ID值。其中key值是一个32位的整型数据。
key值有两种途径获取:1.key值可以人为的指定。但这样可能会造成同一个IPC机制有相同的可以值,为了解决这个问题Linux系统提供了系统调用。2.ftok()可以创建key。此函数的声明如下:
// come from /usr/include/sys/ipc.h
key_t ftok(const char* pathname, int id);
第1个参数pathname为文件路径,可以是普通文件路径也可以是目录路径,但必须为当前系统存在的路径;
第2个参数id为一个int型变量。
每个文件都有其自身的属性,可以通过stat()函数读取,在ftok()函数创建key时,使用了该文件属性的st_dev(文件设备编号)和st_ino(文件节点),key的具体构成如下所示:
key值的31~24(共8bit)为ftok()第2个参数的低8位;
key值的23~16(共8bit)为该文件st_dev属性的低8位;
key值的15~0(共16bit)为该文件st_ino属性的低16位。
因此,ftok()使用相同的参数将得到的key是完全相同的。同一个key值创建某类IPC机制将得到同一个IPC机制。可以使用相同key值创建的不同类的IPC,即使用相同的key值分别创建一个消息队列和一下信号量,两者是没有联系的。下面给出使用ftok()创建key值的示例:
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <sys/ipc.h>
#define PATHNAME "/"
int main()
{
key_t key;
struct stat buf;
if (stat(PATHNAME, &buf) == -1) {
perror("stat error");
return -1;
}
printf("file st_dev:%x\n", buf.st_dev);
printf("file st_ino:%x\n", buf.st_ino);
key = ftok(PATHNAME, 3);
printf("\nkey=%x\n", key);
printf("key>>24=%x\n", key>>24);
printf("(key>>16)&0xff=%x\n", (key>>16)&0xff); // st_dev
printf("key&0xffff=%x\n", key&0xffff); // st_ino
return 0;
}
运行结果如下所示:
上图运行结果完全符合key值的构成。
三、拥有者及权限
要访问任何一个IPC工具需要对该IPC工具拥有相应的权限,该结构为struct ipc_perm
定义在/usr/include/bits/ipc.h文件
中。具体实现如下:
/* Data structure used to pass permission information to IPC operations. */
struct ipc_perm
{
__key_t __key; /* Key. */ // Key值
__uid_t uid; /* Owner's user ID. */ // 拥有者ID
__gid_t gid; /* Owner's group ID. */ // 拥有者组ID
__uid_t cuid; /* Creator's user ID. */ // 创建者ID
__gid_t cgid; /* Creator's group ID. */ // 创建者组ID
unsigned short int mode; /* Read/write permission. */ // 读写权限
unsigned short int __pad1;
unsigned short int __seq; /* Sequence number. */
unsigned short int __pad2;
__syscall_ulong_t __glibc_reserved1;
__syscall_ulong_t __glibc_reserved2;
};