System V IPC

1. 概述

有三种类型的IPC称为System V IPC:
- System V 消息队列
- System V 信号量
- System V共享内存
之所以称为System V IPC是因为这三种IPC机制都是来源于System V Unix的实现。

消息队列信号量共享内存
头文件<sys/msg.h><sys/sem.h><sys/shm.h>
创建或者打开IPC函数msggetsemgetshmget
控制IPC操作函数msgctlsemctlshmctl
IPC操作函数msgsnd/msgrcvsemopshmat/shmdt
key_t 键和ftok函数

三种System V IPC都使用key_t的类型作为它们的名字, 头文件定义在<sys/types.h>中,定位为一个无符号的长整型数,可以 通过ftok()函数获取,或者统一定义在一个头文件中(不能有重复的)。

//NAME
//  ftok - convert a pathname and a project identifier to a System V IPC key
//SYNOPSIS
       #include <sys/types.h>
       #include <sys/ipc.h>

       key_t ftok(const char *pathname, int proj_id);
       // success return System V IPC key, otherwise return -1

注意点:

  1. pathname指定的文件必须要存在,因为ftok函数会使用指定的文件的st_devst_inoproj_id共同生成一个key
  2. proj_id只会使用到低8位, 但是不能为0。

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

  1. pathname所在的文件系统的信息(stat结构体的st_dev信息)。
  2. 该文件在文件系统中的索引节点号(stat结构体的st_ino成员)。
  3. proj_id的低序8bit(不能为0)。

索引节点不能为0是因为IPC_PRIVATE定义为0.

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



int main(int argc, char *argv[])
{
	struct stat st;

	if (argc != 2) {
		fprintf(stderr, "usage: ftok <pathname>\n");
		return -1;
	}

	stat(argv[1], &st);

	printf("st_dev: %lx\nst_ino: %lx\nkey: %x\n", 
		(unsigned long)st.st_dev, (unsigned long)st.st_ino, (unsigned int)ftok(argv[1], 0x57));

	return 0;
}

st_dev: 805
st_ino: a5cd2
key: 57055cd2

由执行结果可知: ftok计算key值为proj_id在高8位, st_dev中年12位IPC的键的接下来的12bit, st_ino在低12bit,

ipc_perm结构

内核给每一个IPC对象维护一个信息表,其内容跟内核给文件维护的信息类似。

struct ipc_perm {
       key_t          __key;       /* Key supplied to msgget(2) */
       uid_t          uid;         /* Effective UID of owner */
       gid_t          gid;         /* Effective GID of owner */
       uid_t          cuid;        /* Effective UID of creator */
       gid_t          cgid;        /* Effective GID of creator */
       unsigned short mode;        /* Permissions */
       unsigned short __seq;       /* Sequence number */
 };

该结构体以及System V IPC函数使用的较为明显的常值定义在<sys/ipc.h>头文件中。

创建与打开IPC通道

创建或者打开一个IPC对象的三个getXXX函数的第一个参数都是key_t的IPC键值,返回值为identifier是一个整型标识符。对于key值,应用程序有两种选择:

  • 调用ftok函数,给它传递一个pathname和id.
  • 指定key为IPC_PRIVATE, 这将保证会创建一个新的,唯一的IPC对象。

在这里插入图片描述
所有的getXXX函数都有一个名为oflag的参数,它指定了IPC对象的读写权限(ipc_perm中的mode域),并选择是创建一个新的IPC对象还是访问一个已经存在的IPC对象。选择规则如下:

  • 指定keyIPC_PRIVATE能保证创建一个IPC对象,没有一对id和pathname的组合导致ftok参数IPC_PRIVATE这个键值。
  • 设置oflag参数的IPC_CREAT为但是不设置IPC_EXCL位时,如果所指定的键的IPC对象不存在则创建一个新的IPC对象,否则返回该IPC对象。
  • 同时设置IPC_CREAT和IPC_EXCL位, 如果指定的IPC对象不存在,则创建一个新的IPC对象,如果存在,返回一个EEXIST错误,因为该IPC对象存在。

设置IPC_EXCL但是不设置IPC_CREAT是没有意义的,也就是说不能单独使用IPC_EXCL

在这里插入图片描述

oflagkey不存在key已存在
无特殊标志出错 errno=ENOENT成功,引用存在对象
IPC_CREAT成功,创建IPC对象成功,引用存在对象
IPC_CREAT or IPC_EXCL成功,创建IPC对象失败, errno= EEXIST

注意: IPC创建了自己的IPC_XX常值,不同于open函数的O_CREAT和O_EXCL.

IPC权限

当使用get_xxx函数创建IPC对象时(使用IPC_CREAT),以下信息保存在该对象的ipc_perm结构中。

  1. oflag中的某些位初始化ipc_perm中的mode成员。下标展示了System V 三种不同IPC机制的权限位:
    在这里插入图片描述

  2. cuidcgid成为分别设置为调用进程的有效用户ID和有效组ID, 这两个成员合称为创建者ID(creator ID).

  3. ipc_perm结构中的uidgid成员也分别设置为调用进程的有效用户id和有效组id, 这两个成员合称为属主id(owner id)。

每当一个进程访问某个IPC对象时,IPC就执行两次检查,该IPC被打开时检查一次,以后每使用该对象就检查一次。

标识符重用

ipc_perm结构还包含一个名为seq的变量,它是一个槽位使用情况序列号,该变量是一个由内核为系统中每个潜在的IPC对象维护一个计数器,每当删除一个IPC对象时,内核就会递增相应的槽位标识,若溢出则循环回0.

ipcs和ipcrm程序

由于System V IPC三种类型不是以文件系统中的路径名标识,因此使用标准的ls和rm程序无法看到他们,也无法删除它们, 因此提供了两个特殊的程序: ipcsipcrm
ipcs: 查看各种IPC信息。
ipcrm: 删除IPC对象。

总结
  1. msgget/semget/shmget第一个参数都是key键值。
  2. 如果指定IPC_PRIVATE则创建一个新的,唯一的IPC对象。
  3. 需要区分IPC_CREATIPC_EXCL的使用。
  4. ipc_permoflag参数的关系。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值