protobuf协议长连接.docx
《protobuf协议长连接.docx》由会员分享,可在线阅读,更多相关《protobuf协议长连接.docx(7页珍藏版)》请在冰豆网上搜索。
protobuf协议长连接
竭诚为您提供优质文档/双击可除
protobuf,协议,长连接
篇一:
protobuf协议公优缺点
class="txt">一.什么是protobuf
protocolbuffers是google公司开发的一种数据描述语言
可用于数据存储、通信协议等方面,它不依赖于语言和平台并且可扩展性极强。
现阶段官方支持c++、jaVa、python等三种编程语言,但可以找到大量的几乎涵盖所有语言的第三方拓展包。
消息格式定义采用proto文,google内部应用
优点
一、二进制消息,性能好/效率高(空间和时间效率都很不错)
二、proto文件生成目标代码,简单易用
三、序列化反序列化直接对应程序中的数据类,不需要解析后在进行映射(xml,json都是这种方式)
四、支持向前兼容(新加字段采用默认值)和向后兼容(忽略新加字段),简化升级
五、支持多种语言(可以把proto文件看做idl文件)
六、netty等一些框架集成了protobuf,你可以定义自己的数据结构,然后使用代码生成器生成的代码来读写这个数据结构。
你甚至可以在无需重新部署程序的情况下更新数据结构。
只需使用protobuf对数据结构进行一次描述,即可利用各种不同语言或从各种不同数据流中对你的结构化数据轻松读写。
它有一个非常棒的特性,即“向后”兼容性好,人们不必破坏已部署的、依靠“老”数据格式的程序就可以对数据结构进行升级。
这样您的程序就可以不必担心因为消息结构的改变而造成的大规模的代码重构或者迁移的问题。
因为添加新的消息中的field并不会引起已经发布的程序的任何改变。
缺点
二进制可读性差(貌似提供了
默认不具备动态特性(可以通过动态定义生成消息类型或者动态编译支持)
只涉及序列化和反序列化技术,不涉及Rpc功能(类似xml或者json的解析器)
篇二:
protobuf消息定义原则
1
网络通信涉及到消息的定义,不管是使用二进制模式、xml、json等格式。
消息都可以大体的分为命令消息、请求消息、应答消息和指示消息4大消息类型。
一般情况下每个消息还还有包含一个序列号和一个能够唯一区分类型类型的消息编号,编号可以使用字符串、整数或者枚举等。
1.使用protobuf的enum定于消息的编号,也就是消息的类型。
我会为每个系统都定义一个msg枚举。
包含系统用到的所有消息的枚举编号
01enummsg
02{
03login_Request=0x00001001;
04login_Response=0x00001002;
05
06xxx_Request=0x00001003;
07xxx_Request=0x00001004;
08
09xxx_command=0x000020xx;
10
11xxx_indication=0x00003001;
12}
2.会为每个具有消息体的消息定义一个对应的
protobufmessage。
例如login_Request会有一个对应loginRequest消息。
1messageloginRequest
2{
3requiredbytesusername=1;
4requiredstringpassword=2;
5}
3.会为每个消息大类定义一个消息,例如命令消息全部包含在messagecommand中,请求消息全部包含在Request消息中,应答消息全部包含在
Response消息中,指示消息全部包含在indication消息中。
也就是我会有下面4个protobufmessage:
01messagecommand
02{//包含所有的xxxcommand消息
03}
04messageRequest
05{//包含所有的xxxRequest消息
06}
07messageResponse
08{//包含所有的Response消息
09}
10messageindication
11{//包含所有的indication消息。
12}
4.对于应答消息,并非总是成功的,因此在应答消息中还会包含另外2个字段。
一个用于描述应答是否成功,一个用于描述失败时的字符串信息。
对于有多个应答的消息来说,可能会包含是否为最后一个应答消息的标识。
应答的序号(类似与网络数据包被分包以
后,协议要合并时,需要知道分片在包中的具体位置)。
因此Response看起来想这样:
1messageResponse
2{
3requiredboolresult=1;
4optionalbyteserror_description=2;
5requiredboollast_block=3;
6requiredfixed32block_index=4;
7.....//其他的字段为xxxResponse..
8}5.最后我会定义一个大消息,把command、
Request、Response、indication全部封装在一起,让后在通信的时候都动大消息开始编解码。
大消息看起来想下面这样。
。
01messagemessage
02{
03requiredmsgtype=1;
04requiredfixed32sequence=2;
05
06optionalRequestrequest=3;
07optionalResponseresponse=4;
08optionalcommandcommand=5;
09optionalindicationindication=6;
10}
6.发送数据和接收数据。
用于udp的时候比较简单,因为每个数据包就是一个独立的message消息,可以直接解码,或者编码后直接发送。
但是如果是使用于tcp的时候,由于涉及到粘包、拆包等处理,而且message消息里面也没有包含长度相关的字段(不好处理),因此把message编码后的消息嵌入另外一个二进制消息中。
使用4字节消息长度+message(二进制数据)+(2字节cRc校验(可选))
其中4字节的内容,只包含message的长度,不包含自身和cRc的长度。
如果需要也可以包含,当要记得通信双方必须一致。
6.消息处理(c++)
编解码后,根据message.type字段,可以知道要处理的消息,进行分发。
不过一般情况下我不喜欢if、switch。
所以我比较倾向于使用虚函数来处理。
因此一般情况下我会定义一下的处理方法。
01#pragmaonce
02
03#include
04#include
05#include
06
07#include"client.h"
08
篇三:
protobuf使用例子
protobuf使用例子
1.protobuf使用整理
protobuf序列化反序列化的一种解决方案,protobuf处理成二进制数据流,相比较xml/json更加节省数据流量。
protobuf是google提出的解决方案,有比较多的互联网公司采用此种解决方案,protobuf只支持java/python/php支持语言相对比较少。
protobuf提供了protobuf-java-xx.jar工具包处理,要求开发者定义.proto文件,然后进行执行编译成对应语言版本的源文件,比如java是编译生成.java源文件。
1.1.proto文件编写
protobuf中的proto文件编写,比如定义一个helloworld.proto文件//helloworld.proto文件为:
//定义生成java文件所在的包名
optionjava_package="com.helloworld.protocol";
//生成对应外部类名称
optionjava_outer_classname="helloworldprotoc";
messagehelloworld{
//定义必须属性,类型为int32requiredint32num=1;//定义可选属性,类型为int64optionalint64num2=2;//定义可选属性,类型为stringoptionalstringinfo=3;//定义为list,list里边item类型为stringrepeatedstringmobilelist=4;//定义枚举类型,设定default默认值为maleoptionalsextypesextype=5[default=male];//定义一个message对象optionalhelloworldextextinfo=6;enumsextype{male=0;//0-男性Female=1;//1-女性unknown=2;//2-未知}
}messagehelloworldext{requiredint32num=1;optionalint64num2=2;optionalstringinfo=3;}
1.2.执行生成java文件
下载到protobuf生成exe文件,名称为:
protoc.exe可执行文件
编写生成.java文件脚本为:
gen-test.bat内容为:
protoc--java_out=./helloworld.proto
pause
生成.java文件放在当前目录下的com/helloworld/protocol文件夹目录下
protobuf生成源
文件.rar
若在client端-server端开发过程中,比如客户端使用的是android开发,则可以将生成的protocol源文件拷贝给客户端开发了。
通过helloworldprotoc文件进行数据携带传输。
1.3.通过socket进行通信
下载官方提供的protobuf-java.xx.jar包,然后就可以进行开发工作了,简单采用socket进行处理client端请求,server端进行应答处理。
处理过程为:
client发出请求>>>用helloworldproto进行携带数据,转换成二进制数据流server端接收请求>>>反序列化>>>对象>>>序列化>>>传输回给客户端
代码压缩包为:
socket方式实现
数据传输例子.rar
//helloworldclient.java文件为:
publicclasshelloworldclient{
privatefinalstaticstringhost_name="localhost";
privatefinalstaticintpoRt=8080;
publicstaticvoidmain(string[]args){
socketsocket=null;
inputstreamins=null;
outputstreamous=null;
try{
socket=newsocket(host_name,poRt);
socket.setkeepalive(true);
socket.setsotimeout(10000);
ous=socket.getoutputstream();
ins=socket.getinputstream();
helloworld.builderbuilder=helloworld.newbuilder();builder.setnum
(1);
builder.setnum2(2l);
helloworldext.builderextbuilder=helloworldext.newbuilder();
extbuilder.setinfo("helloworldext");
extbuilder.setnum
(1);
extbuilder.setnum2(2l);
builder.setextinfo(extbuilder.build());
//先写length长度,然后写byte[]字节数组
//通过tobytearray方法序列化成二进制数据
byte[]bytes=builder.build().tobytearray();
intlength=bytes.length;
ous.write(length);
ous.write(bytes);
ous.flush();
system.out.println("length="+length);
system.out.println("builder="
builder.build().tostring());
//先读length长度,然后读byte[]字节数组
intreadlength=ins.read();
byte[]readbytes=newbyte[readlength];
ins.read(readbytes,0,readlength);
//这种读法导致阻塞了
//while(ins.read(readbytes)!
=-1){
//system.out.println("reading");
//}
//通过parseFrom方法反序列为java对象
system.out.println("readlength="+readlength);
helloworldhelloworld=helloworld.parseFrom(readbytes);+
system.out.println("extinfo="
helloworld.getextinfo().getinfo());
}catch(unknownhostexceptione){
e.printstacktrace();
}catch(ioexceptione){
e.printstacktrace();
}finally{
if(socket!
=null){
try{
socket.close();
}catch(ioexceptione){
e.printstacktrace();
}
}
if(ins!
=null){
try{
ins.close();
}catch(ioexceptione){
e.printstacktrace();
}
}
if(ous!
=null){
try{
ous.close();
}catch(ioexceptione){
e.printstacktrace();
}
}
}
}
}
//helloworldserver.java文件为:
publicclasshelloworldserver{
privatefinalstaticintpoRt=8080;
publicstaticvoidmain(string[]args){
serversocketserver=null;
inputstreamins=null;
outputstreamous=null;
socketsocket=null;
try{
server=newserversocket(poRt);+
system.out.println("serverstartupsuccess");
socket=server.accept();
ins=socket.getinputstream();
ous=socket.getoutputstream();
intlength=ins.read();
byte[]bytes=newbyte[length];
ins.read(bytes,0,length);
//这种读法导致阻塞了
//while
(ins.read(bytes)!
=-1){
//}
helloworldhelloworld=helloworld.parseFrom(bytes);system.out.println(helloworld.tostring());
ous.write(length);
ous.write(bytes);
ous.flush();
system.out.println("serverwritesuccess");
}catch(ioexceptione){
e.printstacktrace();
}finally{
if(server!
=null){
try{
server.close();
}catch(ioexceptione){
e.printstacktrace();
}
}
if(socket!
=null){
try{
socket.close();
}catch(ioexceptione){
e.printstacktrace();
}
}
if(ins!
=null){
try{
ins.close();
}catch(ioexceptione){
e.printstacktrace();
}
}