ftok()函数解析

ftok

消息队列信号灯共享内存常用在Linux服务端编程的进程间通信环境中。而此三类编程函数在实际项目中都是用System V IPC函数实现的。System V IPC函数名称和说明如下表15-1所示。

表15-1 System V IPC函数

 

消息队列

信号灯

共享内存区

头文件

<sys/msg.h>

<sys/sem.h>

<sys/shm.h>

创建或打开IPC函数

msgget

semget

shmget

控制IPC操作的函数

msgctl

semctl

shmctl

IPC操作函数

msgsnd

msgrcv

semop

shmat

shmdt

1.key_t键和ftok函数

函数ftok把一个已存在的路径名和一个整数标识符转换成一个key_t值,称为IPC键值(也称IPC key键值)。ftok函数原型及说明如下:

key_t ftok( char * fname, int id )

              ftok(把一个已存在的路径名和一个整数标识符转换成IPC键值)

 

所需头文件

#include <sys/types.h>

#include <sys/ipc.h>

函数说明

把从pathname导出的信息与id的低序8位组合成一个整数IPC键

函数原型

key_t ftok(const char *pathname, int proj_id)

函数传入值

pathname:指定的文件,此文件必须存在且可存取

proj_id:计划代号(project ID)

函数返回值

成功:返回key_t值(即IPC 键值)

出错:-1,错误原因存于error中

附加说明

key_t一般为32位的int型的重定义

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

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

上述三个值的组合产生一个32位键。

2. ftok函数代码举例

ftok.c源代码如下:

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

int main(int argc, char **argv)
{
    struct stat stat1 ;
    
    if ( argc != 2 )
    {
        printf("usage: ftok < pathname >" ) ;
        exit(1) ;
    }

    stat( argv[1], &stat1 ) ;

    printf("st_dev:%lx, st_ino:%lx, key:%x\n",  (unsigned long)stat1.st_dev, (unsigned long)stat1.st_ino , ftok(argv[1],0x579 )) ;
    printf("st_dev:%lx, st_ino:%lx, key:%x\n",  (unsigned long)stat1.st_dev, (unsigned long)stat1.st_ino , ftok(argv[1],0x118 )) ;
    printf("st_dev:%lx, st_ino:%lx, key:%x\n",  (unsigned long)stat1.st_dev, (unsigned long)stat1.st_ino , ftok(argv[1],0x22 )) ;
    printf("st_dev:%lx, st_ino:%lx, key:%x\n",  (unsigned long)stat1.st_dev, (unsigned long)stat1.st_ino , ftok(argv[1],0x33 )) ;
   
    exit(0) ;
}

编译 gcc ftok.c –o ftok
运行 ./ftok /tmp,执行结果如下:

从上面程序可以看出,通过ftok返回的是根据文件(pathname)信息和计划编号(proj_id)合成的IPC key键值,从而避免用户使用key值的冲突。proj_id值的意义让一个文件也能生成多个IPC key键值。ftok利用同一文件最多可得到IPC key键值0xff(即256)个,因为ftok只取proj_id值二进制的后8位,即16进制的后两位与文件信息合成IPC key键值。

有关该函数的三个常见问题:

  1. pathname是目录还是文件的具体路径,是否可以随便设置;
  2. pathname指定的目录或文件的权限是否有要求;
  3. proj_id是否可以随便设定,有什么限制条件。

解答:

  1. ftok根据路径名,提取文件信息,再根据这些文件信息及project ID合成key,该路径可以随便设置。
  2.  该路径是必须存在的,ftok只是根据文件inode在系统内的唯一性来取一个数值,和文件的权限无关。
  3.  proj_id是可以根据自己的约定,随意设置。这个数字,有的称之为project ID; 在UNIX系统上,它的取值是1到255;

关于ftok()函数的一个陷阱

  • 在使用ftok()函数时,里面有两个参数,即fname和id,fname为指定的文件名,而id为子序列号,这个函数的返回值就是key,它与指定的文件的索引节点号和子序列号id有关,这样就会给我们一个误解,即只要文件的路径,名称和子序列号不变,那么得到的key值永远就不会变。
  •  事实上,这种认识是错误的,想想一下,假如存在这样一种情况:在访问同一共享内存的多个进程先后调用ftok()时间段中,如果fname指向的文件或者目录被删除而且又重新创建,那么文件系统会赋予这个同名文件新的i节点信息,于是这些进程调用的ftok()都能正常返回,但键值key却不一定相同了。由此可能造成的后果是,原本这些进程意图访问一个相同的共享内存对象,然而由于它们各自得到的键值不同,实际上进程指向的共享内存不再一致;如果这些共享内存都得到创建,则在整个应用运行的过程中表面上不会报出任何错误,然而通过一个共享内存对象进行数据传输的目 的将无法实现。
  • 所以要确保key值不变,要么确保ftok()的文件不被删除,要么不用ftok(),指定一个固定的key值
  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值