在IPC中中,我们经常事情ftok函数来获取key,来作为获取消息队列id、共享存储标识和信号量ID。在项目中使用了php进程和linux进程通信,采用了消息队列的方式,但是结果表现为php中的ftok和linux中的ftok函数返回key却不一样。如下分析。
实例
php中运行下代码
$intKey = ftok("/home/work/orp/msg/tmp", 1); echo dechex($intKey) . " ";
得到的结果为
311007e1
用c运行以下代码
intKey = ftok("/home/work/orp/msg/tmp", 1); printf("%x", intKey);
得到的结果为
11007e1
显然得到的结果不一致,与我们预期不一样。为什么会出现这种情况,下面解答。
源码分析
1、在php源码
找到/php/ext/standard/ftok.c文件查看ftok函数源码,如下
调用的c的ftok函数的第二参数为 proj[0] 。
2、hhvm中的源码
文件路径/php/ext/standard/ftok.c, 查看ftok函数如下:
调用的c的ftok函数的第二参数为 (int)proj[0] 。
3、demo测试这种两种用法
#include <stdio.h> #include <string.h> #include <sys/ipc.h> int main(int argc, char const *argv[]) { char proj[1]; strcpy(proj, argv[1]); printf("key1 %d ", (int)proj[0]); printf("key2 %d ", proj[0]); printf("key3 %s ", proj); }
运行结果为:
$ a.out 1
key1 49
key2 49
key3 1
$ a.out a
key1 97
key2 97
key3 a
翻阅ASCII码表可知
1 的ASCII码为 49
a 的ASCII码为 97
总结
1、从demo测试的来看,源码中的 (int)proj[0] 和 proj[0] 这两种写法得到的是 某个字符的ASCII码,所以在php中使用ftok生成的 key 来做为消息队列、共享存储和信号量与Linux进程通信,是有问题的。除非在linux端的程序指定 ftok 的 proj 参数为 php中对应参数的ASCII码值。如将实例的中C代码改为:
intKey = ftok("/home/work/orp/msg/tmp", 49); printf("%x", intKey);
再次运行,得到
311007e1
与php中一直了,符合要求。
2、这其实是php中的ftok函数实现的问题