python使用protobuf协议传输固定格式协议数据
protobuf是什么
protobuf 是google开源的一个序列化框架,类似xml,json,最大的特点是基于二进制,比传统的XML表示同样一段内容要短小得多。还可以定义一些可选字段,用于服务端与客户端通信
protobuf在工作中的运用
背景:由于我们业务开发主要是C++,在进行测试时,业务流程很长,经常会自己写数据到mq,而mq的内容更多是pb(protobuf简称)协议,所以我需要模拟pb协议,往mq中写数据,现在我们就先看如何写pb协议的数据,如果我们不按照PB协议传输,那么消费方是不能正常消费的
potobuf文件
开发给到的编译的文件一般都会是.potobuf文件,.potobuf文件内容是这个样子。我摘取了部分主要的关键内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | 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文件
1 | protoc - - python_out = . / . / jpush_protocol.proto |
本地就生成了.py文件
python文件如何调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | #-*- 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) |
代码解读,实例大类(入口类)
1 | msg_ctrl = jpush_protocol_pb2.JPushProtocol() 实例这个大类,得到实例对象,从协议中我们可以看到JPushProtocol包含了JPushProtocolHead,JPushProtocolBody, |
获取变量的方法,比如协议中需要调用到JPushProtocolHead中ver的字段,那么就是这样使用
1 2 3 4 | msg_ctrl.head.ver = 0 大类的实例对象.实例对象.字段 <br>我是这样理解<br> message JPushProtocol<br> {<br> optional JPushProtocolHead head = 1 ; #head 实际是JPushProtocolHead 实例对象,要使用它类下的方法,可直接使用实例对象名.方法名 optional JPushProtocolBody body = 2; #body 实际是JPushProtocolBody 实例对象<br> } |
要用到什么字段,就使用大类实例对象.实例对象.字段=值,这样就可以了,运行,生成数据,数据就生成了,往MQ插入数据,会专门写一篇,rabbitmq的生产和消费,结合使用
PB文件的嵌套
以上可能是比较简单的使用,在很多情况下,一个message下会嵌套很多message,而message下在继续嵌套多个message,比如以下PB文件
需要使用JPushBatchMsg,调用JPushProtocol,在调用JPushProtocolHead和JPushProtocolBody
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | 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 ; } |
它的使用就有些区别,使用是这样
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | #-*- 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() 方法,得到一个实例对象,在使用实例对象,去调用所需的方法就行
1 2 | j = jpush_protocol_pb2.JPushBatchMsg() msg_ctrl = j.element.add() |
嵌套就是有一个大盒子,然后把每个类(小盒子)通过element.add()添加到大盒子中,然后小盒子使用就如单个方法使用就行
在推荐一篇我觉得写的也很清楚的文章可做参考:https://www.jianshu.com/p/1aeb8ee87b99
作者:做梦的人(小姐姐) 出处:https://www.cnblogs.com/chongyou/ 本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。 如果文中有什么错误,欢迎指出。以免更多的人被误导。 微信号:18582559217 |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架