-- 基于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)net版 Protobuf编译器下载地址.
.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)java版protobuf编译器下载地址.
步骤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());
}