使用protobuf实现跨语言序列化 Java和Python实例
首先下载安装protoc
对于OS X可以通过brew直接安装 brew install protobuf
安装完可以通过protoc --version查看版本信息
创建proto文件-带Any类型的版本
带Any类型的只能导出pb2类型的Python文件,没法导出Python3 的版本,暂时不知道如何解决
Any类型的字段可以在java中实现泛型的功能
MessageDto.proto
syntax = "proto3";
import "google/protobuf/any.proto";
message MessageDto {
string action=1;
int32 statte=2;
google.protobuf.Any data=3;
}
RpcCmd.proto
syntax = "proto3";
import "MessageDto.proto";
message RpcCmd {
MessageDto message=1;
string randomKey=2;
string remoteAddressKey=3;
}
Point2PointMessage.proto
syntax = "proto3";
message Point2PointMessage {
string targetAddressKey;
string message;
}
BytesData.proto
syntax = "proto3";
message BytesData {
bytes content=1;
}
导出相应的对象定义文件
Python版
protoc --python_out=./gen_pb2 RpcCmd.proto MessageDto.proto Point2PointMessage.proto BytesData.proto
生成的文件名为XXX_pb2.py
Java版
protoc --java_out=./gen_java RpcCmd.proto MessageDto.proto Point2PointMessage.proto BytesData.proto
生成的文件名为XXXOuterClass.java
在Python中使用
首先要导入生成的文件,放到自己喜欢的包下,然后修改导入包的地址,比如RpcCmd_pb2.py中修改
import com.tony.proto.py2.MessageDto_pb2 as MessageDto__pb2
然后开始使用
from com.tony.proto.py2 import RpcCmd_pb2, Point2PointMessage_pb2, BytesData_pb2, MessageDto_pb2
def serialize_to_file(file_path):
p2p_msg = Point2PointMessage_pb2.Point2PointMessage()
p2p_msg.message = "Hello, p2p from python"
p2p_msg.targetAddressKey = "/127.0.0.1:38211"
# bytes_data = BytesData_pb2.BytesData()
# bytes_data.content = b"Hello, bytes data from python"
rpc_cmd = RpcCmd_pb2.RpcCmd()
rpc_cmd.randomKey = "random-key-key-random"
rpc_cmd.remoteAddressKey = "/127.0.0.1:1234"
rpc_cmd.message.action = "p2p"
rpc_cmd.message.state = 100
rpc_cmd.message.data.Pack(p2p_msg)
# rpc_cmd.message.data.Pack(bytes_data)
bytes_write = rpc_cmd.SerializeToString()
fw = open(file_path, mode="wb")
fw.write(bytes_write)
fw.flush()
fw.close()
print("write bytes to file:", bytes_write)
def deserialize_from_file(file_path):
fo = open(file_path, mode="rb")
bytes_read = fo.read()
fo.close()
print("read bytes from file:", bytes_read)
rpc_cmd = RpcCmd_pb2.RpcCmd()
rpc_cmd.ParseFromString(bytes_read)
print(rpc_cmd)
p2p_msg = Point2PointMessage_pb2.Point2PointMessage()
# bytes_data = BytesData_pb2.BytesData()
# rpc_cmd.message.data.Unpack(bytes_data)
rpc_cmd.message.data.Unpack(p2p_msg)
print("msg_content:", p2p_msg.message)
print("msg_target:", p2p_msg.targetAddressKey)
# print("bytes_data:", str(bytes_data.content, 'utf-8'))
if __name__ == "__main__":
serialize_file_path = "/trans-data-pb2.dat"
serialize_to_file(serialize_file_path)
deserialize_from_file(serialize_file_path)
执行结果如下,可以将bytes_data相关的注释取消同时注释掉p2p_msg相关的测试BytesData类型的序列化和反序列化
write bytes to file: b'\n]\n\x03p2p\x10d\x1aT\n&type.googleapis.com/Point2PointMessage\x12*\n\x10/127.0.0.1:38211\x12\x16Hello, p2p from python\x12\x15random-key-key-random\x1a\x0f/127.0.0.1:1234'
read bytes from file: b'\n]\n\x03p2p\x10d\x1aT\n&type.googleapis.com/Point2PointMessage\x12*\n\x10/127.0.0.1:38211\x12\x16Hello, p2p from python\x12\x15random-key-key-random\x1a\x0f/127.0.0.1:1234'
message {
action: "p2p"
state: 100
data {
type_url: "type.googleapis.com/Point2PointMessage"
value: "\n\020/127.0.0.1:38211\022\026Hello, p2p from python"
}
}
randomKey: "random-key-key-random"
remoteAddressKey: "/127.0.0.1:1234"
msg_content: Hello, p2p from python
msg_target: /127.0.0.1:38211
在Java中使用
同样导入到喜欢的包下,修改对应的包名即可
@Slf4j
public class ProtobufSerializeDemo {
@Test
public void serializeToFile() throws Exception {
Point2PointMessageOuterClass.Point2PointMessage.Builder p2pMsgBuilder = Point2PointMessageOuterClass.Point2PointMessage.newBuilder();
p2pMsgBuilder.setTargetAddressKey("/127.0.0.1:1233");
p2pMsgBuilder.setMessage("hello from java