PHP接入Protocol Buffer並且實現TCP的二進位制流傳輸

徐漢彬發表於2015-09-20

我們這邊是一個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庫檔案哈。

生成的程式碼:

於是,我們得到了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,這個函式本身就可以用在二進位制讀取。

相關文章