protobuf是什么
protobuf 是google開源的一個序列化框架,類似xml,json,最大的特點是基於二進制,比傳統的XML表示同樣一段內容要短小得多。還可以定義一些可選字段,用於服務端與客戶端通信
protobuf在工作中的運用
背景:由於我們業務開發主要是C++,在進行測試時,業務流程很長,經常會自己寫數據到mq,而mq的內容更多是pb(protobuf簡稱)協議,所以我需要模擬pb協議,往mq中寫數據,現在我們就先看如何寫pb協議的數據,如果我們不按照PB協議傳輸,那么消費方是不能正常消費的
potobuf文件
開發給到的編譯的文件一般都會是.potobuf文件,.potobuf文件內容是這個樣子。我摘取了部分主要的關鍵內容
message JPushProtocol
{
optional JPushProtocolHead head = 1;
optional JPushProtocolBody body = 2;
}
message JPushProtocolHead
{
optional uint32 cmd = 1;
optional uint32 ver = 2;
optional int64 uid = 3;
optional JPushCookie cookie = 4;
optional bytes app_key = 5;
optional uint32 platform = 6;
optional JPushAddr src = 7;
optional JPushAddr dst = 8;
optional int32 rom = 9 [default = 0];
optional bool sync = 10 [default = false]; //absent or false not sync!
optional int64 ctime = 11; //first time what is generated
optional bytes account_id = 12;
}
message JPushPushMessage
{
enum ClientPlatForm{
UNKNOW = 0;
IOS = 1;
ANDROID = 2;
}
optional int32 msg_type = 2;
optional int64 msgid = 3;
optional bytes msg_content = 4;
optional int32 resp_code = 5; //for msg recv
optional int32 msg_flag = 6; //msg cycle msg-flag
optional ClientPlatForm platform = 7[default = UNKNOW];
optional int64 real_uid = 8;
}
如何使用potobuf文件
先要把 python在使用的時候是需要把pb轉換成py文件,使用protobuf這個插件就可以轉換,百度使用有很多案例,如轉換成pb文件
protoc --python_out=./ ./jpush_protocol.proto
本地就生成了.py文件

python文件如何調用
#-*- coding: utf-8 -*-
import string
import pika
import json
import random
import types
import time
import jpush_protocol_pb2
def GetMsgCtrl(appkey, msgid,uid):
msg_ctrl = jpush_protocol_pb2.JPushProtocol()
msg_ctrl.head.ver = 0
msg_ctrl.head.uid = uid
msg_ctrl.head.app_key = appkey
msg_ctrl.head.platform = 0
msg_ctrl.head.rom = 0
msg_ctrl.head.ctime = int(time.time())
msg_ctrl.body.msg.msgid = int(msgid)
msg_ctrl.body.msg.real_uid = int(uid)
msg_ctrl.body.msg.platform = jpush_protocol_pb2.JPushPushMessage.ANDROID
print(msg_ctrl)
str_msg = msg_ctrl.SerializeToString()
pare=msg_ctrl.ParseFromString(str_msg)
print(pare)
print(str_msg)
return str_msg
if __name__ == '__main__':
uid=8023315484
appkey = "ffe45db16405af961ead45a0"
send_msg = GetMsgCtrl(appkey,45035996277483525, uid)
代碼解讀,實例大類(入口類)
msg_ctrl = jpush_protocol_pb2.JPushProtocol() 實例這個大類,得到實例對象,從協議中我們可以看到JPushProtocol包含了JPushProtocolHead,JPushProtocolBody,
獲取變量的方法,比如協議中需要調用到JPushProtocolHead中ver的字段,那么就是這樣使用
msg_ctrl.head.ver = 0 大類的實例對象.實例對象.字段
我是這樣理解
message JPushProtocol
{
optional JPushProtocolHead head = 1; #head 實際是JPushProtocolHead 實例對象,要使用它類下的方法,可直接使用實例對象名.方法名
optional JPushProtocolBody body = 2; #body 實際是JPushProtocolBody 實例對象
}
要用到什么字段,就使用大類實例對象.實例對象.字段=值,這樣就可以了,運行,生成數據,數據就生成了,往MQ插入數據,會專門寫一篇,rabbitmq的生產和消費,結合使用

PB文件的嵌套
以上可能是比較簡單的使用,在很多情況下,一個message下會嵌套很多message,而message下在繼續嵌套多個message,比如以下PB文件
需要使用JPushBatchMsg,調用JPushProtocol,在調用JPushProtocolHead和JPushProtocolBody
message JPushBatchMsg
{
repeated JPushProtocol element = 1;
}
message JPushProtocol
{
optional JPushProtocolHead head = 1;
optional JPushProtocolBody body = 2;
}
message JPushProtocolHead
{
optional uint32 cmd = 1;
optional uint32 ver = 2;
optional int64 uid = 3;
optional JPushCookie cookie = 4;
optional bytes app_key = 5;
optional uint32 platform = 6;
optional JPushAddr src = 7;
optional JPushAddr dst = 8;
optional int32 rom = 9 [default = 0];
optional bool sync = 10 [default = false]; //absent or false not sync!
optional int64 ctime = 11; //first time what is generated
optional bytes account_id = 12;
}
message JPushProtocolBody
{
optional JPushReg reg = 1;
optional JPushLogin login = 2;
optional JPushPushMessage msg = 3;
optional JPushTagalias tagalias = 4;
optional JPushDTokenReport dtoken = 5;
optional JPushIDFAReport idfa = 6;
optional JPushCtrlCmd ctrl = 7;//this protocol head cmd filed is 25
optional JPushUserCtrl user_ctrl = 8;
optional JPushRidReport rid_report = 9;
optional JPushShareChannelCmd sc_cmd = 10;
}
它的使用就有些區別,使用是這樣
#-*- coding: utf-8 -*-
import string
import pika
import json
import random
import types
import time
import jpush_protocol_pb2
j=jpush_protocol_pb2.JPushBatchMsg()
msg_ctrl=j.element.add()
def GetMsgCtrl(appkey, msgid,uid):
msg_ctrl.head.ver = 0
msg_ctrl.head.uid = uid
msg_ctrl.head.app_key = appkey
msg_ctrl.head.platform = 2
msg_ctrl.head.rom = 0
msg_ctrl.head.ctime = int(time.time())
msg_ctrl.body.msg.msgid = int(msgid)
msg_ctrl.body.msg.real_uid = int(uid)
msg_ctrl.body.msg.platform = 2
print(msg_ctrl)
str_msg = j.SerializeToString()
return str_msg
if __name__ == '__main__':
uid=8023315484
appkey = "ffe45db16405af961ead45a0"
send_msg = GetMsgCtrl(appkey,45035996277483525, uid)
嵌套與沒有嵌套區別在使用上,是這樣,在實例最入口的大類后,需要用實例變量調用j.element.add() 方法,得到一個實例對象,在使用實例對象,去調用所需的方法就行
j=jpush_protocol_pb2.JPushBatchMsg() msg_ctrl=j.element.add()
嵌套就是有一個大盒子,然后把每個類(小盒子)通過element.add()添加到大盒子中,然后小盒子使用就如單個方法使用就行
在推薦一篇我覺得寫的也很清楚的文章可做參考:https://www.jianshu.com/p/1aeb8ee87b99
