对码当歌,猿生几何?

Linux和PHP中的ftok函数返回值不一致问题跟踪

在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函数源码,如下

image.png

调用的c的ftok函数的第二参数为 proj[0] 。

2、hhvm中的源码

文件路径/php/ext/standard/ftok.c, 查看ftok函数如下:

image.png

调用的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函数实现的问题