使用原因
在不同语言的前后端交互时,由于不能直接调用,所以必须有一套相同的读写协议来规定数据的格式,也就是说,在服务器与客户端交互时,将要传输的内容按照规定模式转化为一种中间语言(byte数组),然后在另一端根据同样的格式转换回自己语言的对象,在这个过程中,可能会出现一些问题,如:
- 协议的内容需要繁琐的交流协商,以保证双方一致。
- 很可能出现在失误的情况下,导致数据对错位问题。
- 在协议变更的时候,双方都要进行修改,这是一种潜藏的隐患。
- 可能由于不同语言之间,变量类型的不同导致双方结果不同。
而Protobuf的出现,解决了这样一种隐患。首先Protobuf是用一种独立的Protob语言写的,简单易懂,并且从这一层直接去除掉语法错误问题;接着,Protobuff可以通过需要编译成不同的语言,从这一层解决了双方不一致和变更时衍生的问题。
定义Protobuf
在这里咱们简单的介绍一下Protobuf的几个常用语法:
package protocol;
import "Member.proto";
option java_package = "protocol.Data";
message UserItem{
enum Sex{
MALE = 0;
FEMALE = 1;
}
required string userName = 1;
required Sex sex = 2;
optional int32 father = 3;
repeated PersonalInfo personalInfo = 4;
}
咱们来解释一下这里面的代码分别是什么意思:
import "Member.proto";
表示导入另一个Protobuf,这样就可以使用里面定义的message
对象PersonalInfo
了。
option java_package = "protocol.Data";
表示将这个写好的Protobuf文件在编译时编译如protocol/Data文件夹下。
message UserItem
表示对象的名称,比如编译成Java文件后,就是叫做UserItem.java的文件。
enum Sex
是一个枚举的使用,下面就用到了这个Sex
。
required string userName = 1;
表示UserItem
这个对象中有一个叫userName
的参数,参数类型是String
,requested
表示在使用时,这个参数必须被填入,否则将报错!
optional
与requested
使用方式类似,表示在使用中这个参数可填可不填。
repeated PersonalInfo personalInfo = 4
中的repeated
则表示这个参数可能有多个(可以没有),PersonalInfo
类型来自import "Member.proto";
。
注意:.proto文件不能与定义的对象名(在这里是UserItem)相同,否则会编译失败!帖主就在此栽过跟头。o(>﹏<)o
使用
这里只介绍Java中对于Protobuf的使用(可参考《迷你微信》服务器),想了解C#对Protobuf的使用,请参考《迷你微信》客户端。
开始
想要在Java中使用Protobuf,首先要定义好Protobuf,然后用控制台指令进行编译,控制台在.proto文件的地址下,输入protoc --java_out=./ ./(我的proto文件名).proto
运行成功后,会在制定目录下出现(我的proto文件名).java
文件,将其复制到你的Java项目中就可以使用了。
创建
当你要将你的数据转化为Protobuf对象时,需要这样创建:
import UserItemMsg;
..........
// 创建
UserItemMsg.UserItem.Builder builder = UserItemMsg.UserItem.newBuilder();
// 设置数值
builder.setUserName = "枫露霜阳";
builder.setSex(UserItemMsg.UserItem.Sex.MALE);
builder.addPhone = "18252060997";
builder.addPhone = "110";
// 要build起来
UserItemMsg uim = builder.build();
// 若是要转成byte数组
byte[] byteArray = uim.toByteArray();
上述代码将Protobuf在java中的类创建、设值、build、转为byte数组,最后用于网络传输。
反解
上面将Protobuf的Java类转化为byte数组,然后通过网络传输,到了接收端,如何将其解回Java对象呢?
import UserItemMsg;
...............
// 得到传过来的byte数组
byte[] byteArray = fromClientByteArray;
UserItemMsg.UserItem userItem = UserItemMsg.UserItem.parseFrom(byteArray);
// 获取数值
String userName = userItem.getUserName();
后话
至此,我们就把Protobuf的简单使用描述了一遍,若想看看帖主项目的详细使用请戳下面传送门。