回顾了一下以前的实验,一直不理解为什么在消息队列中要使用ftok,比如下面的一个实例
if((key=ftok(".",'a'))==-1){
perror("ftok");
exit(1); }
qid=msgget( key, IPC_CREAT | 0666 ); /*创建一个消息队列*/
if ( qid < 0 ) { /* 创建一个消息队列失败 */
perror ( "msgget" );
exit (1) ;
}
printf ("created queue id : %d \n", qid ); /* 输出消息队列的ID */
要先生成一个key,再调用msgget()得到消息队列的id。
搜了百度百科的一段贴在下面先建立起对ftok基本的了解:
key_t ftok( const char * fname, int id )
fname就是你指定的文件名(已经存在的文件名),一般使用当前目录,如:
key_t key;
key = ftok(“.”, 1); 这样就是将fname设为当前目录。
id是子序号。
在一般的UNIX实现中,是将文件的索引节点号取出,前面加上子序号得到key_t的返回值。
如指定文件的索引节点号为65538,换算成16进制为0x010002,而你指定的ID值为38,换算成16进制为0x26,则最后的key_t返回值为0x26010002。
为什么要使用ftok()函数(可以如此记忆:file to key)把一个已存在的路径名和一个整数标识符转换成一个key_t值?我的理解就是:现在假如有两个应用程序处于同一目录下,并且这两个应用程序要通过一个消息队列进行通信,现在第一个应用程序开起来,通过msgget()得到了一个消息队列id,而第二个应用程序怎么知道是使用这个消息队列id进行通信呢?
第一种方法如下所示:
./send ,让这个进程输出它所创建的消息队列id,比如输出11111. 再./receive 11111,运行第二个程序,11111当成参数传入。在receive这个程序里面要将argv[1]当成消息队列的id,这种方法缺点很明显,每次都要手动输入。
第二种方法就是ftok了,利用ftok得到一个键值,这个键值只和inode有关,并且在第二应用程序里面也写上实例中的代码,则两个应用程序能得到相同的键值,之后通过这个键值能得到内核中的消息队列的id,而msgget()的参数单独使用IPC_CREAT时,要么返回一个新创建的消息队列的标识符,要么返回具有相同关键字值的队列的标识符。所以第一个程序调用msgget()会根据这个键值创建出消息队列id,而第二个程序使用相同的键值调用msgget()能得到这个键值对应的消息队列的id,这样就不用向方法一那样手动输入了。
总结下就是消息队列id是一个进程的内部名,自己创建的一个消息队列id其他进程怎么会知道呢!所以为使得多个合作进程能够在同一个消息队列对象上会合,需要一个外部名方案,那就是使用了键(key),对于相同的路径每个进程能得到相同的键值,内核再根据这个键值能得到消息队列id。