【轉載】 原文鏈接: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;
簡單驗證:
用到的代碼,文件wxyuan.c:
#include <stdio.h> #include <sys/sem.h> #include <stdlib.h> int main() { key_t semkey; if((semkey = ftok("./test", 1))<0) { printf("ftok failed\n"); exit(EXIT_FAILURE); } printf("ftok ok ,semkey = %d\n", semkey); return 0; }
關於ftok()函數的一個陷阱
在使用ftok()函數時,里面有兩個參數,即fname和id,fname為指定的文件名,而id為子序列號,這個函數的返回值就是key,它與指定的文件的索引節點號和子序列號id有關,這樣就會給我們一個誤解,即只要文件的路徑,名稱和子序列號不變,那么得到的key值永遠就不會變。
事實上,這種認識是錯誤的,想想一下,假如存在這樣一種情況:在訪問同一共享內存的多個進程先后調用ftok()時間段中,如果fname指向的文件或者目錄被刪除而且又重新創建,那么文件系統會賦予這個同名文件新的i節點信息,於是這些進程調用的ftok()都能正常返回,但鍵值key卻不一定相同了。由此可能造成的后果是,原本這些進程意圖訪問一個相同的共享內存對象,然而由於它們各自得到的鍵值不同,實際上進程指向的共享內存不再一致;如果這些共享內存都得到創建,則在整個應用運行的過程中表面上不會報出任何錯誤,然而通過一個共享內存對象進行數據傳輸的目 的將無法實現。
這是一個很重要的問題,希望能謹記!!!
所以要確保key值不變,要么確保ftok()的文件不被刪除,要么不用ftok(),指定一個固定的key值。
Ubuntu下,ftok()產生鍵值的原理:
執行該源碼:
#include <stdio.h> #include <stdlib.h> #include <sys/stat.h> int main() { char filename[50]; struct stat buf; int ret; strcpy( filename, "/home/satellite/" ); ret = stat( filename, &buf ); if( ret ) { printf( "stat error\n" ); return -1; } printf( "the file info: ftok( filename, 0x27 ) = %x, st_ino = %x, st_dev= %x\n", ftok( filename, 0x27 ), buf.st_ino, buf.st_dev ); return 0; }
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的后四位構成的。