最近解碼了一個沒有協議(.proto)文件的probuf包,遇到了以下的一些問題:
- 不清楚probuf的基礎知識;
- 不清楚probuf的序列換和反序列化規則;
- 沒有合適的調試工具;
- 不熟悉java裏probuf流的操作;
解決了以上幾個問題,問題也就迎刃而解了!
一、不清楚probuf的基礎知識
官方定義:
protocol buffers 是一種語言無關、平臺無關、可擴展的序列化結構數據的方法,它可用於(數據)通信協議、數據存儲等。
Protocol Buffers 是一種靈活,高效,自動化機制的結構數據序列化方法-可類比 XML,但是比 XML 更小(3 ~ 10倍)、更快(20 ~ 100倍)、更爲簡單。
你可以定義數據的結構,然後使用特殊生成的源代碼輕鬆的在各種數據流中使用各種語言進行編寫和讀取結構數據。你甚至可以更新數據結構,而不破壞由舊數據結構編譯的已部署程序。
主要瞭解到protobuf的基礎定義,使用場景,一些規則,再結合一個實例這塊就算解決了。
詳細介紹可以在以下地方瞭解:
probuf詳解:https://blog.csdn.net/weixin_42018112/article/details/89633837
深入 ProtoBuf - 簡介:https://www.jianshu.com/p/a24c88c0526a
ProtoBuf結合java快速入門:https://www.jianshu.com/p/bb3ac7e5834e
二、不清楚probuf的序列換和反序列化規則
正常情況下我們需要協議文件,也就是生成probuf流時建立的 .proto文件,根據這個文件,我們可以解出來Message對應的每個字段的信息。官方給了一個命令,可以在無 .proto文件的情況下,解出probuf流的內容: protoc --decode_raw。
import subprocess
def decode(data):
process = subprocess.Popen([r'D:\protobuf\protoc.exe', '--decode_raw'],
stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
output = error = None
try:
output, error = process.communicate(data)
except OSError:
pass
finally:
if process.poll() != 0:
process.wait()
return output
f = open(r"D:\testprotobuf.bin", "rb")
data = f.read()
print('data:/n',decode(data))
詳細介紹可以在以下地方瞭解:
無protobuf協議情況下的反序列化------貌似無解, 其實有解!:https://blog.csdn.net/stpeace/article/details/53047424
protobuf流的反解析Message:https://blog.csdn.net/liujiayu2/article/details/77838761
三、沒有合適的調試工具
瞭解完基礎知識以後,我們就可以動手進行解碼的嘗試了。由於網上沒有一些在線的工具(像beJSON)可以輔助我們判斷自己的嘗試是否正確,直接在代碼裏嘗試,每一次修改,啓動,都不太好確定是哪裏出了問題,所以我們先在一些在線調試工具中確定了我們的probuf流是正確的,我們推導出的.proto文件也是正確的,再進行編碼。
我們現有的protobuf流是一個16進制的流:
08 d0 02 10 c3 80 80 80 80 80 80 02 1a 0e 0a 0c e5 be ae e8 bd af e9 9b 85 e9 bb 91 22 4c 08 bd f3 0b 12 06 e8 8a ac e5 85 b0 1a 18 77 c9 35 5a 0e 0c 3b 40 1c d7 c2 bc c7 2b 50 40 00 00 00 00 00 00 2c 40 20 00 50 ff ff ff ff ff ff ff ff ff 01 59 00 00 00 00 00 00 3e 40 60 80 80 80 f8 0f 68 00 70 1e 78 ff ff ff ff 0f 22 4f 08 a1 f4 0b 12 09 e4 b9 8c e5 85 8b e5 85 b0 1a 18 02 37 db 85 e6 7a 40 40 b0 59 3c 87 32 80 48 40 57 b3 09 97 5c 3b 5f 40 20 00 50 ff ff ff ff ff ff ff ff ff 01 59 00 00 00 00 00 00 3e 40 60 80 80 80 f8 0f 68 00 70 1e 78 ff ff ff ff 0f
通過兩個工具:Protobuf Decoder 和 Online Protobuf encoder/decoder,就可以很方便的確定我們的probuf流是否正確,我們推導出的.proto文件是否正確。Protobuf Decoder不需要協議文件(.proto)可以解析出我們的數據內容,Online Protobuf encoder/decoder可以判斷我們推導出的協議文件是否正確。
上述工具資源地址:
無協議文件解碼工具decode:https://download.csdn.net/download/qq_25073789/12334831
通過協議文件編碼解碼流工具: https://download.csdn.net/download/qq_25073789/12334839
四、不熟悉java裏probuf流的操作
proto文件準備就緒,java代碼也通過protoc命令生成後,我們讀取16進制流文件對其進行反序列化。反序列化的接受格式爲byte[],所有我們使用BufferedInputStream進行文件讀取,以下代碼爲讀取probuf流的方法。反序列化和生成java文件的方法參考教程。
public static byte[] readFile(File file) throws Exception {
if (file.exists() && file.isFile()) {
long fileLength = file.length();
if (fileLength > 0L) {
BufferedInputStream fis = new BufferedInputStream(new FileInputStream(file));
byte[] b = new byte[(int) fileLength];
fis.read(b);
fis.close();
fis = null;
return b;
}
} else {
return null;
}
return null;
}
java代碼參考:
java中使用ProtoBuf的Demo: https://www.cnblogs.com/jpfss/p/10881357.html