原标题 PHP接入Protocol Buffer并且实现TCP的二进制流传输
我们这边是一个PHP的Web系统,需要新接入一个业务,是通过Protocol Buffer协议通信,而且只提供了一个C++的接入例子。 对于我们的PHP系统来说,除了接入Protocol Buffer之外,还需要处理二进制流的TCP传输通信,而PHP实际上并不太擅长做这些事情。
PHP版本的Protocol Buffer接入,有官方的支持实现版本。
Protocol Buffer for PHP:
https://code.google.com/p/pb4php/
这里需要注意的点,就是安全中心提供的proto文件里面有一些东西是我们的PHP无法识别的。
(1)头部的package,无法识别直接注释掉。
(2)pb_parser文件里的标量类型做一下调整,之后就可以顺利生成我们需要使用的PHP库文件哈。
生成的代码:
1
2
3
|
require_once ( './parser/pb_parser.php' ); $test = new PBParser(); $test ->parse( 'scintf.proto' ); |
于是,我们得到了PHP使用的库文件pb_proto_scintf.php,下一步就是编写实际的程序代码。
我们经常使用PHP来做字符串的socket通信,但是,处理这种二进制格式的socket传输,PHP并不太擅长。
我们也只能通过pack/unpack的方式,来将字符串转为二进制流。将传输字符串pack为二进制,传输出去,获取回包后,在unpack为字符串,再进行处理。
http://php.net/manual/zh/function.pack.php
在这里,因为我们的PHP是安装了内部的扩展的,我们刚开始犯了一个小错误,就是直接使用了内部类,读取socket回包内容直接使用了read_line(内部实现其实是fgets)。这种做法,会引起2个问题:
(1)当TCP传输只有1个内容数据包的时候,read_line能够读取全部内容,在后续的unpack操作中,一切正常那个。但是,当TCP传 输的超过1个内容数据包的时候,read_line只能读取到第一个包的内容,后面的包没有获取到,在unpack的时候,会报头部解析出来的长度和实际 数据内容大小对不上。
这个有点奇怪的现象,我们是通过tcpdump抓包分析后发现的:
(2)read_line是按照行读取内容,而二进制流中不会以换行符结束,因此,这里还会引起read socket timeout,虽然我们也能顺利读取到内容。
解决的方式,其实也很简单,就是直接使用fread,这个函数本身就可以用在二进制读取。