這幾天在寫一個服務端的socket的通信服務器,以前是本身定義的協議由於,由於只是android客戶端和服務器通信,後來iOS也鏈接到這個socket服務器上,爲了跨語言通信,發現Google的 ProtoBuf(Protocol Buffer)支持跨語言通信,並且效率很是高。javascript
Google Protocol Buffer( 簡稱 Protobuf) 是 Google 公司內部的混合語言數據標準,後來纔開源的,它是一個靈活、高效、結構化的序列化數據結構,它與傳統的XML等通信相比,它的更小、更快、更簡單。java
1.protoBuf在Google內部長期使用,產品穩定成熟,不少商業的項目都選擇使用
2.跨語言,它支持Java、C++、Python、ObJect-c、C#、Go等語言,
3.protoBuf編碼後消息更小、有利於存儲傳輸
4.編碼和解碼的效率很是之高
5.支持不一樣版本的協議向前兼容
6.支持自定義可選和必選字段
android
這裏使用Java語言實現,咱們首選要定義一個protoBuf格式的通信協議,Login.proto文件git
package test;
option java_package = "sg.com.protobuf";
option java_outer_classname = "LoginProto";
message Login{
required int32 id = 1;
required string name = 2;
required string pws = 3;
optional string email = 4;
}複製代碼
package:指定生成Java代碼文件的包名
java_package:指定生Java類的包名
java_outer_classname:指定生成Java代碼的外部類名稱。若是沒有指定該選項,Java代碼的外部類名稱爲當前文件的文件名部分,同時還要將文件名轉換爲駝峯格式,如:my_project.proto
message:protoBuf消息定義的關鍵字,至關於Java中的class
required:數據類型的前綴,表示該字段爲必要字段,既在序列化和反序列化以前該字段必須已經被賦值
repeated:表示這個字段的值能夠容許被重複屢次,若是轉換成JAVA代碼,此filed數據結構爲list,有序的。能夠在「repeated」類型的filed後使用「packed」--壓縮,提升數據傳輸的效率。
optional: 表示這個值是可選的容許爲null
ProtoBuf類型和Java類型對應關係
github
完成消息的定義以後,就能夠經過protoc.exe編譯了
數組
LoginProto.Login.Builder builder = LoginProto.Login.newBuilder();
builder.setId(1);
builder.setName("sgtest");
builder.setPws("123");
builder.setEmail("test@163.com");
//獲取login的實例
LoginProto.Login login = builder.build();
System.out.println(login);
//序列化
System.out.println("---------");
byte[] bytes = login.toByteArray();
System.out.println("leng:"+bytes.length);
login =LoginProto.Login.parseFrom(bytes);
System.out.println(login);複製代碼
實例化一個對象是很是方便的,使用Google給咱們生成的靜態方法就能夠,經過toByteArray()方法來實現序列,parseFrom(bytes)方法來實現反序列化,你會看到protoBuf序列化後的字節長度很是小,這個還不算強大的,下面再來看一中序列化的方式:服務器
//第二種序列化
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
login.writeDelimitedTo(byteArrayOutputStream);
//反序列化
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
login = LoginProto.Login.parseDelimitedFrom(byteArrayInputStream);
System.out.println(login.getEmail());複製代碼
作過大量socket數據傳輸的同窗都知道,socket很容易發生粘包、拆包的問題,會致使數據解析錯誤,protoBuf能夠搞定它,login.writeDelimitedTo(byteArrayOutputStream)方法,將一個對象序列化輸出到一個字節數組流中,它在序列化的字節數組以前,添加一個varint32的數字表示字節數組的長度,因此實際放在字節數據中內容應該是數據的長度加上數據的內容,下面是該方法的源碼
網絡