最近小编在做服务端压力测试的时候,发现服务端与客户端的数据传输是protobuf格式的。压测时需要用Python去序列化请求的protobuf数据,之前有大神搞过这方面的工作,参照大神的步骤一步一步往下走,小编发现自己的项目中有一点儿不同之处:protobuf中有repeated修饰符,对带有这个修饰符的数据进行序列化的时候有一点儿小技巧,小编在这儿跟大家做个分享。
P.s.关于protobuf(Google Protocol Buffer)基本信息,大家可以参见另一位亲爱的小伙伴昨天发的文章:Protobuf不可不知的秘密。
一、关于protobuf中的repeated
repeated是protobuf中的一种限定修饰符,从字面意思看有“重复”的意思,实际上它就是用来指定某一个字段可以存放同一个类型的多个数据(当然也可以是0个或者1个),相当于C++中的vector或者Java中的List。repeated类型数据在protobuf中的定义非常简单:
messagePerson{
requiredstringname = 1;
requiredint32age = 2;
}
messageGroup{
repeatedPerson person = 1;
}
它相当于C++中的vector:
classPerson
{
public:
// balabala...
private:
stringname;
intage;
}
vector<Person> vGroup;
二、Python如何序列化repeated修饰的数据
在利用Python操作protobuf之前,我们需要先编译protobuf文件,让它生成一个.py文件,将这个文件引入到我们的项目中再进行操作。protobuf文件的编译很简单,直接在命令行执行以下命令即可:
protoc.exe -I=./ --python_out=./ yourprotofile.proto
执行之后会在当前执行的目录下生成对应的.py文件(当然输出路径是可以自己指定的):
yourprotofile_pb2.py
将生成的.py文件导入项目中即可使用Python操作这个protobuf了。
下面聊聊如何序列化repeated修饰的数据。对于repeated修饰的数据,小编执行过程中发现需要分两种情况去处理,否则会遇到很棘手的问题(别问我为什么知道,都是泪)。
1.repeated修饰消息体(message)的情况
下图是小编最近遇到的一个.proto文件:

可以看到在ClientRequestBody消息体中,对Data数据使用了repeated修饰符进行了修饰。这种情况下用Python序列化的时候,需要做下面几件事儿:
a.对复合类型(message),调用add方法初始化新实例;
b.对该实例中的每一个元素进行赋值。
用伪代码可以这样表示:
importmyproto_pb2
# 初始化ClientRequestBody实例
clientRequestBody = myproto_pb2.ClientRequestBody()
# 由于Data是复合类型,这儿需要调用add()方法实例化一个Data
mydata = clientRequestBody.data.add()
# 再给mydata中的每一个元素进行赋值
mydata.py = balabala_1
mydata.word = balabala_2
...
这样就完成了Python对复合类型peotobuf数据的操作。小编本以为这是一个通用的办法,当第二天遇到另一个项目的protobuf时,直接套用了上面的做法,发现报错了。查资料后得知,不是所有的类型都可以用上述办法搞定,这就是第二种情况了。
2.repeated修饰标准数据类型的情况
另外一个.proto文件是这样的:
可以看到这个proto文件很简单,ClientRequestBody中只有一个int32类型(相当于C++或Java中的int类型)用repeated修饰了。小编按照上面的办法调用add()方法之后系统报错了。为什么会报错呢?
原来是这样,如果要操作符合数据类型,我们需要对这个数据类型进行实例化;但是如果要操作的数据是一个基本数据类型(比如这种情况下的int32),那么我们直接用append()方法追加新元素即可。伪代码表示如下:
importmyproto_pb2
# 同样,先初始化ClientRequestBody实例
clientRequestBody = myproto_pb2.ClientRequestBody()
# 由于是基本数据类型,这儿就不需要实例化了,直接追加数据即可
clientRequestBody.ids.append( 1)
clientRequestBody.ids.append( 2)
...
# 如果ids需要的数据类型是列表,用extend()方法即可
# 具体参见extend()和append()方法的区别
clientRequestBody.ids.extend(list1)
clientRequestBody.ids.extend(list2)
...
以上是小编最近几天做压力测试过程中遇到的问题和找到的解决方案,希望能给大家提供一点帮助。
关于上述两种序列化的情况,如果大家有更好的解决方法或者有其他疑问,欢迎在留言区留言,另外,关于protobuf的任何问题也欢迎大家留言交流,共同学习。
看都看完了,点个赞呗~么么哒。返回搜狐,查看更多