; ;

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

posted @   做梦的人-  阅读(1951)  评论(2编辑  收藏  举报
编辑推荐:
· 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 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示