• 网络游戏的前后端通讯(一)


    【旧博客转移 - 发布于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)
    待续...

  • 相关阅读:
    通过Appium获取iOS应用元素定位的方法
    如何关闭 iPhone的“Automation Running”滚动?
    推荐一款非常牛的二维码生成器
    VNC Viewer 如何复制黏贴文本
    关于远程Mac电脑
    PyCharm 部署与配置 Vue 项目
    Xcode编译失败(build failed) 但是没有报错
    java怎么根据用户设定的时间执行定时任务
    【hyperf2.2】Hyperf框架 基于JsonRpc与Consul的微服务搭建
    Windows Phone 应用之虾米电台
  • 原文地址:https://www.cnblogs.com/lijiajia/p/6860925.html
Copyright © 2020-2023  润新知