【舊博客轉移 - 發布於2015年9月14日 22:25】
通訊是網絡游戲的最重要部分之一,好的游戲通訊協議設計包括一下特點:包體積小、解析速度快、支持加解密等等,下面就簡單說一下通訊協議的設計
1.游戲中常用的通訊協議以及數據格式
HTTP:
早期的SLG游戲一般會采用HTTP協議進行通訊,后端大多采用PHP,通訊格式用XML、JSON等字符串,由於HTTP是短鏈接,所以沒辦法做到服務端主動更新數據推送給客戶端,那種需要實時更新的數據,一般都采用客戶端定時請求來實現。
Tcp/IP:
隨之MMO游戲興起,對游戲實時交互的要求越來越高,Tcp這種長連接協議被廣泛采用,通過Socket接口,我們可以跟服務端建立起長連接,這種雙向連接很方便實時交互以及服務端主動推送數據,基於這種協議的通訊格式可以是XML、JSON,但大部分都采用直接把對象序列化成二進制的方式傳輸。常用的二進制序列化格式有AMF(Adobe公司創造)、protobuf(谷歌創造)。protobuf由於包體積小,解析速度快等優勢被廣泛使用,當然也可以自己去實現一套通訊格式。
2.自定義格式的序列化跟反序列化
序列化就是把一個對象以某種形式編碼成二進制,用於存儲或者傳輸。
反序列化顧名思義就是把二進制數據解碼成對象。
復合型數據(自定義對象)都會由一些基本數據類型組成,我把它們分為固定長度型跟動態長度型
固定長度如:
byte(8位), short(16位), int(32位), float(32位), long(64位), boolean(8位)
不固定長度:
String, Array
下面是一個把基礎類型轉換成二進制的工具類,String類型的話就要先寫長度再寫UTF數據
1 package com.util; 2 3 import java.io.ByteArrayInputStream; 4 import java.io.ByteArrayOutputStream; 5 import java.io.IOException; 6 import java.io.UnsupportedEncodingException; 7 /** 8 * 二進制工具類 9 * @author lijia 10 */ 11 public class ByteArrayUtil { 12 13 /** 14 * 把字符串轉換成byte[] 15 * @param str 字符串 16 * **/ 17 public static byte[] writeUTF(String str){ 18 ByteArrayOutputStream byteArr = new ByteArrayOutputStream(); 19 byte[] rb = null; 20 try { 21 if(str == null || str == ""){//字符串為空 22 byteArr.write(writeInt(0));//寫入長度為0 23 }else{ 24 byte[] strbyte = str.getBytes("UTF-8"); 25 byteArr.write(writeInt(strbyte.length));//寫入字符串長度 26 byteArr.write(strbyte);//寫入字符串二進制數據 27 } 28 rb = byteArr.toByteArray(); 29 byteArr.close(); 30 } catch (UnsupportedEncodingException e) { 31 e.printStackTrace(); 32 } catch (IOException e) { 33 e.printStackTrace(); 34 } 35 return rb; 36 } 37 38 /** 39 * 讀取字符串 40 * **/ 41 public static String readUTF(ByteArrayInputStream ips){ 42 int strLen = readInt(ips);//先讀長度 43 String str = ""; 44 if(strLen>0) 45 try { 46 byte[] strByte = new byte[strLen]; 47 ips.read(strByte, 0, strLen); 48 str = new String(strByte, "UTF-8"); 49 } catch (UnsupportedEncodingException e) { 50 e.printStackTrace(); 51 } 52 return str; 53 } 54 55 public static byte[] writeLong(long s) { 56 byte[] buf = new byte[8]; 57 for (int i = 8 - 1; i >= 0; i--) { 58 buf[i] = (byte) (s & 0x00000000000000ff); 59 s >>= 8; 60 } 61 return buf; 62 } 63 64 public static long readLong(ByteArrayInputStream ips){ 65 byte[] buf = new byte[8]; 66 ips.read(buf, 0, 8); 67 long r = 0; 68 for (int i = 0; i < 8; i++) { 69 r <<= 8; 70 r |= (buf[i] & 0x00000000000000ff); 71 } 72 return r; 73 } 74 75 public static byte[] writeInt(int s) { 76 byte[] buf = new byte[4]; 77 for (int i = 4 - 1; i >= 0; i--){ 78 buf[i] = (byte) (s & 0x000000ff); 79 s >>= 8; 80 } 81 return buf; 82 } 83 84 public static int readInt(ByteArrayInputStream ips) { 85 byte[] buf = new byte[4]; 86 ips.read(buf, 0, 4); 87 int r = 0; 88 for (int i = 0; i < 4; i++) { 89 r <<= 8; 90 r |= (buf[i] & 0x000000ff); 91 } 92 return r; 93 } 94 95 /**** 96 * 連接兩個字節數組 97 * @param b 98 * @param b2 99 * @return 100 */ 101 public static byte[] connectByteArray(byte[] b, byte[] b2){ 102 int blen = b.length; 103 int b2len = b2.length; 104 byte[] nb = new byte[blen+b2len]; 105 for(int i = 0; i < blen; i++){ 106 nb[i] = b[i]; 107 } 108 for(int i = 0; i < b2len; i++){ 109 nb[blen+i] = b2[i]; 110 } 111 return nb; 112 } 113 }
下面這個P_User的類包含三個屬性:id,age,isVip
兩個函數:
ToBinary
按照一定的順序把對象的各個成員屬性轉換成二進制寫入流中
FromBinary
按照順序把二進制轉換成真實數據
package com.coolProto; public class P_User extends Message { public P_User() { } public int age; public double id; public boolean isVip; @Override public void ToBinary(MessageOutputByteArray osData) { write_int(osData, this.age); write_double(osData, this.id); write_boolean(osData, this.isVip); } @Override public void FromBinary(MessageInputByteArray isData) { this.age = read_int(isData); this.id = read_double(isData); this.isVip= read_boolean(isData); } }
這樣就可以序列化一個對象了,當然這種類可以寫一個工具自動生成。
用XML做配置
屬性名,屬性類型,值(數組類型用)
<root> <proto name="M_User_List_toc"> <attribute name="id" type="double" value="null"/> <attribute name="a" type="string"/> <attribute name="b" type="string"/> <attribute name="skillList" type="array" value="int"/> <attribute name="userList" type="array" value="P_User"/> </proto> <proto name="P_User"> <attribute name="userName" type="string"/> <attribute name="age" type="int"/> <attribute name="id" type="double"/> <attribute name="isVip" type="boolean"/> </proto> </root>

這是之前寫過的一個工具,用來編輯這種XML配置,支持編譯成三種格式(As3、c#、Java)
待續...

