Protobuf数据交换协议配置

-- 基于Protobuf的高效,跨平台的数据传输,交换,存储协议配置
【官网】:https://github.com/google/protobuf

应用场景

通常情况下,我们采用xml,json进行数据的交换,传输,存储处理...但遇到速度要求更快,且数据不限于文本,且需要很好的支持跨平台,语言无关性的时候: 我们可以选择Protobuf来处理...

基础资源

protobuf编译器,  各个语言的protobuf包

使用须知

使用之前,请仔细了解protobuf的协议语法.. protobuf是具备扩展性,高效率,跨平台,语言无关性的数据交换格式...在开发中的角色类似xml,json.

配置步骤

一.协议格式解释(实际编写协议文本时,请不要包含下列注释符及注释内容).

package tutorial;// package是命名空间,下列的Person是联系人,LinkList是通讯录

option java_package = "com.protobuftest.protobuf";//java的包名,c#的命名空间

option java_outer_classname = "PersonProbuf"; //生成java,c#类的类名

message Person {    //message代表一个类.

required string name = 1; //required是指必须的

required int32 id = 2;

optional string email = 3;//optional是指可选填的

enum PhoneType {

MOBILE = 0;

HOME = 1;

WORK = 2;

}

message PhoneNumber {

required string number = 1;

optional PhoneType type = 2 [default = HOME];//default是默认值

}

repeated PhoneNumber phone = 4;//repeated是指可有多个,集合.

}

message LinkList {

repeated Person person = 1;//表示一个Person的集合.

}

二.数据类型.

.proto Type

Notes

C++ Type

JavaType

PythonType[2]

double

double

double

float

float

float

float

float

int32

Uses variable-length encoding. Inefficient for encoding negative numbers if your field is likely to have negative values, use sint32 instead.

int32

int

int

int64

Uses variable-length encoding. Inefficient for encoding negative numbers if your field is likely to have negative values, use sint64 instead.

int64

long

int/long[3]

uint32

Uses variable-length encoding.

uint32

int[1]

int/long[3]

uint64

Uses variable-length encoding.

uint64

long[1]

int/long[3]

sint32

Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s.

int32

int

int

sint64

Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s.

int64

long

int/long[3]

fixed32

four bytes. More efficient than uint32 if values are often greater than 228.

uint32

int[1]

int

fixed64

eight bytes. More efficient than uint64 ifvalues are often greater than 256.

uint64

long[1]

int/long[3]

sfixed32

Always four bytes.

int32

int

int

sfixed64

Always eight bytes.

int64

long

int/long[3]

bool

bool

boolean

boolean

string

A string must always contain UTF-8 encoded or 7-bit ASCII text.

string

String

str/unicode[4]

bytes

May contain any arbitrary sequence of bytes.

string

ByteString

str

常见问题

  • No syntax specified for the proto file. Please use ‘syntax =
    【解决方案】需要指定版本. syntax=proto2;//proto版本,需要在协议的文件中首行添加 package com.mobilecontrol.pb; //包名
  • 生成的实体类放到c#项目中编译不过,提示一些对象定义重复
    【解决方案】实践证明,协议中的message需要单独放到类文件中进行生成,否则生成的类无法编译通过,存在部分成员的重复定义问题
  • java中能编译通过,但执行对象.newBuilder()出现异常
    【解决方案】发现其中的com.google.protobuf包如果通过jar包引用则很容易出错,但是把包的源代码放到本项目下引用就没问题.
  • 提示”Field number 1 has already been used in "protobuf.testBuf" by field "...."”
    【解决方案】就是字段默认值发生重复了,调整下就好了.
  • Expected top-level statement (e.g. "message")..
    【解决方案】查询问题原因,原来是由于编码格式的问题,因为,我使用UE打开了文件,并保存为UTF-8的形式。因此,会在文件的开头有一个特殊的字符,详见下图: 应该要以Notepad工具,并以utf-8无BOM格式编码

快速入门

[]一个跨平台与语言的protobuf的应用场景示例.

B1)netProtobuf编译器下载地址.

.net 版的protobuf来源于proto社区,有两个版本。一个版本叫protobuf-net,官方站点:http://code.google.com/p/protobuf-net/ 写法上比较符合c#一贯的写法。

另一个版本叫protobuf-csharp-sport 官方站点:http://code.google.com/p/protobuf-csharp-port/ 写法上跟java上的使用极其相似,比较遵循Google 的原生态写法,跨平台选择此版本比较好。因为你会发现几乎和java的写法没啥两样,本篇也是使用这个版本。

http://code.google.com/p/protobuf-csharp-port/下载Win版本.


B2)Protobuf解决方案的编译方法.

1.)构建解决方案:protobuf-csharp-port-masteruilduild.bat,   buildAll.bat

2.)解决方案入口:protobuf-csharp-port-mastersrcProtocolBuffers.sln.

3.)编译方法:打开后选中各个类库单独编译,之后再一起在整个解决方案编译.

4.)编译输出结果:protobuf-csharp-port-masteruild_output ools

B3)Pro协议文件的编译输出方法.

步骤1:预先根据业务场景设计好: msg.proto这种协议文件.

步骤2:  cmd定位到protoc.exe所在目录.

步骤3:运行命令:

命令1

protoc --descriptor_set_out=OutputCSCodemsg.protobin --include_imports InputProtomsg.proto

命令2

protogen OutputCSCodemsg.protobin

B4)c#端的调用.

public void SetLocation(double dLatitude, double dLongtitude)

{

TaskDataForSetLocation.Builder TskDataForSetLocationBuilder = TaskDataForSetLocation.CreateBuilder();

TskDataForSetLocationBuilder.Latitude = dLatitude;

TskDataForSetLocationBuilder.Longitude = dLongtitude;

TaskDataForSetLocation eTskDataForSetLocation = TskDataForSetLocationBuilder.Build();

PhoneTask.Builder phoneTskBuilder = PhoneTask.CreateBuilder();

phoneTskBuilder.TskId = int.Parse(DateTime.Now.ToString("HHmmss"));

phoneTskBuilder.TskType = PhoneTask.Types.TaskType.SetLocation;

phoneTskBuilder.TskData = eTskDataForSetLocation.ToByteString();

PhoneTask ePhoneTsk = phoneTskBuilder.Build();

NetworkStream stream = this._TcpClient.GetClientStream();

if (stream != null)

{

byte[] bytes=ePhoneTsk.ToByteArray();

this._TcpClient.SendData(bytes);

}

}


C1)javaprotobuf编译器下载地址.

步骤1):进入项目:https://github.com/google/protobuf

步骤2.):从中部导航中(Commits,Branches,Release,Constributors)中选择Release点击进入https://github.com/google/protobuf/releases

步骤3.):滚动到指定的版本,选择protoc-x.x.x-win32.zip版本下载,其它的是源代码版本.

里面有一个bin目录,下面包含protoc.exe就是我们要用的编译器.

C2)Pro协议文件的编译输出方法.

步骤1:预先根据业务场景设计好: msg.proto这种协议文件.//如果别的语言已设计好msg.proto这个协议文件(文件名可以自定义),java中无需重复设计,直接拿过来编译生成相关类即可.

步骤2:  cmd定位到protoc.exe所在目录.

步骤3: 运行:protoc.exe --java_out=./ InputProto/msg.proto    //InputProto是和protoc.exe同目录的自建的文件夹.

C3)java端的调用.

PhoneTask ePhoneTask=null;

TaskDataForSetLocation eTaskDataForSetLocation=null;

try {

ePhoneTask=PhoneTask.parseFrom(data);//data是字节数组

eTaskDataForSetLocation=TaskDataForSetLocation.parseFrom(ePhoneTask.getTskData()) ;//.proto格式的协议文件中,一个协议对象嵌入另外一个协议对象,不过嵌入的的数据形式是bytes.

}

catch(Exception ex){

APPLog.LogDebugToFile("CustomTcpNotifyServer.DealClient.RecvPacket.pb转换异常:"+ex.getMessage());

}


参考资料

51La