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

摘要:
交流是网络游戏最重要的部分之一。好的游戏通信协议设计包括以下特点:包大小小、解析速度快、支持加密和解密等。让我们简单谈谈通信协议的设计。1.游戏中常见的通信协议和数据格式是HTTP:早期的SLG游戏通常使用HTTP协议进行通信,后端大多使用PHP,通信格式使用XML、JSON等字符串,因为HTTP是一个短链接,服务器不可能主动更新数据并将其推送到客户端。需要实时更新的数据通常由客户的定期请求实现。
【旧博客转移 - 发布于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>

网络游戏的前后端通讯(一)第1张

网络游戏的前后端通讯(一)第2张


这是之前写过的一个工具,用来编辑这种XML配置,支持编译成三种格式(As3、c#、Java)
待续...

免责声明:文章转载自《网络游戏的前后端通讯(一)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇python数据可视化案例——力导向图,网络图,关系图(使用pyecharts,networkx,echarts,js)...easyPoi 工具类下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

c# 通过程序修改hosts文件

1 根据ip替换 var OSInfo =Environment.OSVersion; string pathpart = "hosts"; if (OSInfo.Platform ==PlatformID.Win32NT) { //is windows NT pathpart = "system32\drivers\etc\hosts";...

JAVA对文件类型的校验

通常,在WEB系统中,上传文件时都需要做文件的类型校验,大致有如下几种方法: 1. 通过后缀名,如exe,jpg,bmp,rar,zip等等。 2. 通过读取文件,获取文件的Content-type来判断。 3. 通过读取文件流,根据文件流中特定的一些字节标识来区分不同类型的文件。 4. 若是图片,则通过缩放来判断,可以缩放的为图片,不可以的则不是。 然而...

Spring中RestTemplate的使用方法

一、REST 在互联网中,我们会通过请求url来对网络上的资源做增删改查等动作,这里的请求包含两部分:动词,主要包括增、删、改、查;名词,就是网络中的各种资源。传统的非REST风格的请求方式是把动词和名词全都放在url中。例如,对设备的操作可能是这样的:添加设备:http://test/device/add删除设备:http://test/device/d...

Android蓝牙开发技术学习总结

Android开发,提供对蓝牙的通讯栈的支持,允许设别和其他的设备进行无线传输数据。应用程序层通过安卓API来调用蓝牙的相关功能,这些API使程序无线连接到蓝牙设备,并拥有P2P或者多端无线连接的特性。 蓝牙的功能: 1、扫描其他蓝牙设备 2、为可配对的蓝牙设备查询蓝牙适配器 3、建立RFCOMM通道(其实就是尼玛的认证) 4、通过服务搜索来链接其他的设备...

C++实现01串排序

题目内容:将01串首先按长度排序,长度相同时,按1的个数从少到多进行排序,1的个数相同时再按ASCII码值排序。 输入描述:输入数据中含有一些01串,01串的长度不大于256个字符。 输出描述:重新排列01串的顺序,使得串按题目描述的方式排序。 题目分析: (1)定义一个多重集合容器,该容器的元素类型为string,采用设定的比较函数 (2)因为元素是st...

Scala学习——模式匹配

scala模式匹配 1.基础match case(类似java里switch case,但功能强大些) object MatchApp { def main(args: Array[String]): Unit = { val is = Array("a","b","c","d") val i = is(Random.nextInt...