[Linux]——浅析ftok函数

原文链接: https://blog.csdn.net/u013485792/article/details/50764224

     

关于ftok函数,先不去了解它的作用来先说说为什么要用它,共享内存,消息队列,信号量它们三个都是找一个中间介质,来进行通信的,这种介质多的是。就是怎么区分出来,就像唯一一个身份证来区分人一样。你随便来一个就行,就是因为这。只要唯一就行,就想起来了文件的设备编号和节点,它是唯一的,但是直接用它来作识别好像不太好,不过可以用它来产生一个号。ftok()就出场了。ftok函数具体形式如下:

    key_t ftok(const char *pathname, int proj_id);

    其中参数fname是指定的文件名,这个文件必须是存在的而且可以访问的。id是子序号,它是一个8bit的整数。即范围是0~255。当函数执行成功,则会返回key_t键值,否则返回-1。在一般的UNIX中,通常是将文件的索引节点取出,然后在前面加上子序号就得到key_t的值。


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

1.pathname是目录还是文件的具体路径,是否可以随便设置

2.pathname指定的目录或文件的权限是否有要求

3.proj_id是否可以随便设定,有什么限制条件


解答:

   1、ftok根据路径名,提取文件信息,再根据这些文件信息及project ID合成key,该路径可以随便设置。

    2、该路径是必须存在的,ftok只是根据文件inode在系统内的唯一性来取一个数值,和文件的权限无关。

    3、proj_id是可以根据自己的约定,随意设置。这个数字,有的称之为project ID; 在UNIX系统上,它的取值是1到255;


简单验证:

                    [Linux]——浅析ftok函数_第1张图片

用到的代码,文件wxyuan.c:


   
   
   
   
  1. #include
  2. #include
  3. #include
  4. int main()
  5. {
  6. key_t semkey;
  7. if((semkey = ftok( "./test", 1))< 0)
  8. {
  9. printf( "ftok failed\n");
  10. exit(EXIT_FAILURE);
  11. }
  12. printf( "ftok ok ,semkey = %d\n", semkey);
  13. return 0;
  14. }

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

     在使用ftok()函数时,里面有两个参数,即fname和id,fname为指定的文件名,而id为子序列号,这个函数的返回值就是key,它与指定的文件的索引节点号和子序列号id有关,这样就会给我们一个误解,即只要文件的路径,名称和子序列号不变,那么得到的key值永远就不会变。

     事实上,这种认识是错误的,想想一下,假如存在这样一种情况:在访问同一共享内存的多个进程先后调用ftok()时间段中,如果fname指向的文件或者目录被删除而且又重新创建,那么文件系统会赋予这个同名文件新的i节点信息,于是这些进程调用的ftok()都能正常返回,但键值key却不一定相同了。由此可能造成的后果是,原本这些进程意图访问一个相同的共享内存对象,然而由于它们各自得到的键值不同,实际上进程指向的共享内存不再一致;如果这些共享内存都得到创建,则在整个应用运行的过程中表面上不会报出任何错误,然而通过一个共享内存对象进行数据传输的目 的将无法实现。

      这是一个很重要的问题,希望能谨记!!!

     所以要确保key值不变,要么确保ftok()的文件不被删除,要么不用ftok(),指定一个固定的key值。


Ubuntu下,ftok()产生键值的原理:


   
   
   
   
  1. #include
  2. #include
  3. #include
  4. int main()
  5. {
  6. char filename[ 50];
  7. struct stat buf;
  8. int ret;
  9. strcpy( filename, "/home/satellite/" );
  10. ret = stat( filename, &buf );
  11. if( ret )
  12. {
  13. printf( "stat error\n" );
  14. return -1;
  15. }
  16. printf( "the file info: ftok( filename, 0x27 ) = %x, st_ino = %x, st_dev= %x\n", ftok( filename, 0x27 ), buf.st_ino, buf.st_dev );
  17. return 0;
  18. }

执行该源码:

satellite@ubuntu:~/test$ ./wxyuan
the file info: ftok( filename, 0x27 ) = 27012eef, st_ino = e2eef, st_dev= 801


通过执行结果可看出,ftok获取的键值是由ftok()函数的第二个参数的后8个bit,st_dev的后两位,st_ino的后四位构成的。


有关 st_devst_ino的定义如下:

   
   
   
   
  1. 函数: int stat( const char *file_name, struct stat *buf )
  2. 函数说明:通过文件名filename,获取文件信息,并保存在buf所指的结构体stat中。
  3. 返回值:成功执行返回 0,失败返回 -1,错误代码存于errno
  4. struct stat结构体的定义如下:
  5. /usr/include/ asm/stat.h
  6. struct stat {
  7. unsigned long st_dev; //文件的设备编号
  8. unsigned long st_ino; //节点
  9. unsigned short st_mode; //文件的类型和存取的权限
  10. unsigned short st_nlink; //连到该文件的硬连接数目,刚建立的文件值为1
  11. unsigned short st_uid; //用户ID
  12. unsigned short st_gid; //组ID
  13. unsigned long st_rdev;
  14. unsigned long st_size;
  15. unsigned long st_blksize;
  16. unsigned long st_blocks;
  17. unsigned long st_atime;
  18. unsigned long st_atime_nsec;
  19. unsigned long st_mtime;
  20. unsigned long st_mtime_nsec;
  21. unsigned long st_ctime;
  22. unsigned long st_ctime_nsec;
  23. unsigned long __unused4;
  24. unsigned long __unused5;
  25. };


笔者补充:更具体的说,ftok其实使用了下面的几个东西来生成key

  • pathname所在文件系统的信息(stat结构的st_dev成员)
  • pathname在本文件系统内的索引节点号(stat结构的st_ino成员)
  • id的低序8位(不能为0)

你可能感兴趣的:(Linux)