網絡游戲的前后端通訊(一)


【舊博客轉移 - 發布於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)
待續...


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM