Unity手遊之路Java版服務端使用protostuff簡化protobuf開發

開發一款網絡遊戲,首先要考慮的是客戶端服務端之間用何種編碼格式進行通信。之前我們介紹了Unity遊戲前端使用protobuf的方法。今天我們來談談服務端如何使protobuf。遊戲服務端語言百花齊放,除了比較傳統的c/c++外,Java,Erlang,Python都有很多團隊在使用。


今天推薦一下Java作爲服務端開發語言。國內很多出色的頁遊和手遊都是採用Java作爲服務端語言的。比如《神曲》《秦美人》《龍將》《時空獵人》

等,不一而足。


本文主要探討如何簡化Protobuf程序的開發。

  • 傳統方式

按照傳統的開發流程,都是如下:


1.先編寫proto文件格式,例如

  1. message Person { 
  2.   required int32 id = 1; 
  3.   required string name = 2; 
  4.   optional string email = 3; 
message Person {
  required int32 id = 1;
  required string name = 2;
  optional string email = 3;
}


2.運行編譯程序,生成實體類Person.java
protoc  --java_out=./src   ./person.proto


3.在程序中可以直接使用Person類的相關函數進行序列化和反序列化

  1. //序列化 
  2. Person person = builder.build(); 
  3. byte[] buf = person.toByteArray(); 
  4. //反序列化 
  5. Person person2 = PersonProbuf.Person.parseFrom(buf); 
//序列化
Person person = builder.build();
byte[] buf = person.toByteArray();
//反序列化
Person person2 = PersonProbuf.Person.parseFrom(buf);

上面的流程看似很方便了,有什麼問題呢?還能不能再改進呢?我們先看看生成的Person類代碼吧,竟然有幾千行。
實際上我們只是包含了3個變量而已,可讀性大大降低了。其次,開發過程每次都得藉助外部的編譯工具來生成代碼。


於是我們可能就有了一個簡單的思路。自己編寫Person的類,然後通過外部的api,直接對這個類進行序列化和反序列化。
直接拋棄了protoc工具。


這個思路,已經有人實現出來了,最早是在c#語言版本的protobuf-net實現了。它利用c#的Attribute(類似Java的Annotation註解)+反射來實現普通實體類的Protobuf序列化和
反序列化。


本想自己把protobuf-net的c#代碼轉換成Java代碼。後來在OverStack中翻到有人介紹Protostuff,正是基於這種思路的。

  • 改進版
1.編寫Person類(爲了使demo代碼精簡,字段都暫時設爲public)
  1. public class Person{ 
  2.     public int id; 
  3.     public String name; 
  4.     public String email; 
public class Person{
	public int id;
	public String name;
	public String email;
}

2.測試序列化和反序列化
  1. public static void main(String[] args) throws IOException { 
  2.         // //類的模式設置爲Person類 
  3.         Schema<Person> schema = RuntimeSchema.getSchema(Person.class); 
  4.         Person person1 = new Person(); 
  5.         person1.id = 10086
  6.         person1.name = "ken"
  7.         person1.email = "[email protected]"
  8.         // 緩存buff 
  9.         LinkedBuffer buffer = LinkedBuffer.allocate(1024); 
  10.         // 序列化成protobuf的二進制數據 
  11.         byte[] data = ProtobufIOUtil.toByteArray(person1, schema, buffer); 
  12.  
  13.  
  14.         // 反序列化 
  15.         Person person2 = new Person(); 
  16.         ProtobufIOUtil.mergeFrom(data, person2, schema); 
  17.         System.out.println(person2.id); 
  18.     } 
public static void main(String[] args) throws IOException {
		// //類的模式設置爲Person類
		Schema<Person> schema = RuntimeSchema.getSchema(Person.class);
		Person person1 = new Person();
		person1.id = 10086;
		person1.name = "ken";
		person1.email = "[email protected]";
		// 緩存buff
		LinkedBuffer buffer = LinkedBuffer.allocate(1024);
		// 序列化成protobuf的二進制數據
		byte[] data = ProtobufIOUtil.toByteArray(person1, schema, buffer);


		// 反序列化
		Person person2 = new Person();
		ProtobufIOUtil.mergeFrom(data, person2, schema);
		System.out.println(person2.id);
	}

更多的功能可以去詳細閱讀相關的手冊吧。比如,指定實體類字段的序列化順序,忽略某些字段不被序列化等等。

  • 性能考慮
一開始,考慮到Protostuff的這種反射,會不會比官方推薦的反射性能差很遠呢?沒有調查,就沒有發言權。有人已經測試了,性能方面還是差不多的,可以放心使用。
具體的測試數據可以去查閱網上相關的數據,在此省略了。

  • 總結

Protostuff的優勢是將開發流程簡化,讓我們可以更高效,更專注地開發。有任何問題歡迎一起探討[email protected]


下一篇,我將會用一個完整的demo,將整個Unity客戶端和服務端的通信流程串聯起來。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章