概念

本教程不讲解TCP/IP协议,Socket属于哪层,消息包体怎么设计等,主讲 egret.WebSocket 使用示例 与 protobuf 使用示例。

在使用egret.WebSocket之前需要简单讨论了解目前几种通信模式。

HTTP

网站中常见的一种传输协议,用于访问页面或资源时,向页面所在的服务器发送一个 HTTP 请求。服务器识别请求,返回响应数据并关闭连接。这过程中客户端不请求,服务器不能主动推送消息到客户端。早些的游戏通过轮训以及 AJAX 实现了不需要手动刷新程序内部轮训请求的伪的长连接。这显然是一个非常不明智的方式。可以想象一下聊天室或人物移动场景中,如果我们使用 HTTP 会是一种什么情况。大量的请求与响应报头额外的数据、延迟不断发生、传输带宽压力不断增加,这对于ARPG等类型游戏是致命的。主要适合对即时性要求不高的游戏类型。

Socket

端游中常见的一种传输协议,套链接。需要了解 Socket 的同学百度一下,它是一个长连接的协议。在完成握手后,连接会一直开着,直到客户端或服务器明确予以关闭。在这过程中,服务器能主动的推送消息到客户端,消息格式可以是进制流以及自定义格式等。后期由于FLASH的兴起,页游中绝大多数都在使用。可以想象一下聊天室或人物移动场景中,我们使用 socket 会是一种什么情况。没有额外的数据、主动的消息推送、低延迟等等。

WebScoket

早期 HTML 中并没有提供 socket 的支持,大型页游项目依靠于 Flash 提供的 Socket API 。随着 HTML5 的制定与完善,WebSocket 被各大浏览器厂商所支持。

WebScoket 与 Socket 的区别在于前者提供了完善的API以及握手的机制,而后者是抽象出来的一种概念,具体的实现对于各种语言都可能不同,例如:我们需要自定义协议体,控制缓存区,连接确认方式等。而在 WebSocket 中,每个消息的传输规范都是定义好的,如消息以 0x00 字节开头,以 0xff 结尾,中间数据采用 UTF-8 编码格式,第一次握手必须使用 ws://xxx 或 wss://xxx 进行,在握手成功后将协议升级为 WebSocket 协议,进行双工的通信。第一次请求走的是 HTTP 请求。由于各种规范的定义与实现,旧有的服务器 Socket 并不适用于 WebSocket 。

实际上,许多语言、框架和服务器都提供了 WebSocket 支持,例如:

egret.WebSocket 使用示例

早期参与或制作游戏项目,对下图一定不陌生,定义消息长度位、消息号以及消息读取规范,客户端根据协议规范以字节形式读取包体:

HML5 的 WebSocket 传输中,并没有定义进制流的传送读取。 egret.WebSocket 中对 HTML5 中 WebSocket 进行封装,实现了对于进制流的传输。

egret.WebSocket 默认是字符串形式接受数据,创建一个 egret.WebSocket 非常简单,由于 egret.WebSocket 对字节流传输的实现,服务器与客户端旧有的协议非常方便移植。以下示例演示了创建 egret.WebSocket :

1.修改项目文件 egretProperties.json 中的 modules ,增加 {"name": "socket"}

2.在项目所在目录执行一次编译引擎 egret build -e

this.socket = new egret.WebSocket();
//设置数据格式为二进制,默认为字符串
this.socket.type = egret.WebSocket.TYPE_BINARY;
//添加收到数据侦听,收到数据会调用此方法
this.socket.addEventListener(egret.ProgressEvent.SOCKET_DATA, this.onReceiveMessage, this);
//添加链接打开侦听,连接成功会调用此方法
this.socket.addEventListener(egret.Event.CONNECT, this.onSocketOpen, this);
//添加链接关闭侦听,手动关闭或者服务器关闭连接会调用此方法
this.socket.addEventListener(egret.Event.CLOSE, this.onSocketClose, this);
//添加异常侦听,出现异常会调用此方法
this.socket.addEventListener(egret.IOErrorEvent.IO_ERROR, this.onSocketError, this);
//连接服务器
this.socket.connect("echo.websocket.org", 80);

当触发 egret.Event.CONNECT 侦听方法 onSocketOpen 时连接服务器成功,可以进行数据发送接收。我们创建一个字节数组,通过writeType写入字符串类型,布尔类型,整形,设置指针为开始0,调用 this.socket.writeBytes 写入数据进行数据发送:

var byte:egret.ByteArray = new egret.ByteArray();
byte.writeUTF("Hello Egret WebSocket");
byte.writeBoolean(false);
byte.writeInt(123);
byte.position = 0;
this.socket.writeBytes(byte, 0, byte.bytesAvailable);
this.socket.flush();

当触发 egret.ProgressEvent.SOCKET_DATA 侦听方法 onReceiveMessage() 时数据接收成功,创建一个字节数组并将 socket 中当前数据读入其中,与发送方式类似,接收使用 readType :

var byte:egret.ByteArray = new egret.ByteArray();
this.socket.readBytes(byte);
var msg:string = byte.readUTF();
var boo:boolean = byte.readBoolean();
var num:number = byte.readInt();

protobuf 使用示例

百度百科 protocolbuffer 介绍,protocolbuffer(以下简称PB)是google 的一种数据交换的格式,它独立于语言,独立于平台。google 提供了三种语言的实现:java、c++ 和 python,每一种实现都包含了相应语言的编译器以及库文件。由于它是一种二进制的格式,比使用 xml 进行数据交换快许多。可以把它用于分布式应用之间的数据通信或者异构环境下的数据交换。作为一种效率和兼容性都很优秀的二进制数据传输格式,可以用于诸如网络传输、配置文件、数据存储等诸多领域。

protobuf 被适用于非常多的生产环境中,也出现了各种语言的版本,方便了数据的移植与可维护性。它在部分语言项目中有一定缺陷,如随着项目的不断迭代会产生较多的数据结构类机器码增加项目体积。

这里以第三库的形式加入对 protobufjs 的支持。想了解第三方集成的同学点击:集成第三方JavaScript库

示例下载见教程尾部:

1.拷贝示例项目 libs 目录下 protobuf 目录到新项目所在 libs 目录。

2.拷贝 libsrc 目录下 protobuf 目录到新项目所在 protobuf 目录。

3.项目 egretProperties.json 中增加相关内容。

egretProperties.json:
{
"document_class": "Main",
"modules": [
{
"name": "core"
},
{
"name": "version"
},
{
"name": "res"
},
{
"name": "socket"
},
{
"name": "protobuf",
"path": "libsrc/protobuf"
}
],
"egret_version": "2.0.2"
}

编译引擎,完成对protobuf配置。

在 resource\assets\proto下 ,新建数据文件并命名为 common.proto 。在其中定义我们需要传输的类对象。这个文件在实际生产环境中是服务端客户端公用的,可以有单个或多个根据具体项目而定。通过工具生产对应语言的访问类,如name.ts,并引入项目中,通过 new 或其他方式创建实例。可惜的是目前还没有egret语言所使用的生成工具。

首先在 common.proto 内定义结构体,了解语法点击这里 。我们定义一个简单结构,如:

message Common {
required uint32 id = 1;
required string text = 2;
}

在 resource.js 中我们引入 common.proto 文件,为了方便,在初始化进行加载。也可以使用 RESDepot 工具进行导入。

当文件被加载后,进行数据设置之前需要四步:

1.获取资源数据文件。

2.解码并创建对象构造器。

3.创建需要的数据结构类。

4.实例化数据结构类。

设置与读取示例,如下代码:

var proto: string = RES.getRes("common_proto");
var builder:any = dcodeIO.ProtoBuf.loadProto(proto);
var clazz:any = builder.build("Common");
var data:any = new clazz();
data.set("id",1);//可以使用data.id=1;
data.set("text","oops");//可以使用data.text=oops; console.log("id=" + data.get("id"));
console.log("oops=" + data.get("text"));

我想我写这到这里,不只是为了创建一个文件,序列化数据,反序列化数据,然后创建个实例吧。 好吧,我们继续往下讲,下面就是我们具体使用 egret.WebSocket 发送数据。 这是我们使用它的关键。

在使用上例中 builder.build("Common") 得到对象构造器中提供了序列化的方法 toArrayBuffer() 通过 egret.ByteArray 写入序列化进行传输,在实际的环境中,还需要涉及到一些长度位,校验,消息号等这里不做讨论。发送示例,如下代码:

var arraybuffer: ArrayBuffer = data.toArrayBuffer();
var len: number = arraybuffer.byteLength;
var btyearray:egret.ByteArray=new egret.ByteArray(arraybuffer);
if(len > 0)
{
this.socket.writeBytes(btyearray);
this.socket.flush();
}

接收数据, 我们代码中一直出现 ArrayBuffer 这是JS中一种用于二进制数据存储的类型,与我们的 ByteAarry 相似(ByteAarry封装了ArrayBuffer) 通过 DataView 提供的接口,转换为我们可以使用的 ByteAarray 数据,如下代码:

var msgBuff: ArrayBuffer;
var btyearray: egret.ByteArray = new egret.ByteArray();
this.socket.readBytes(btyearray);
var len = btyearray.buffer.byteLength;
var dataView = new DataView(btyearray.buffer);
var pbView = new DataView(new ArrayBuffer(len));
for(var i = 0;i < len;i++) {
pbView.setInt8(i,dataView.getInt8(i));
}
msgBuff = pbView.buffer; var proto: string = RES.getRes("common_proto");
var builder:any = dcodeIO.ProtoBuf.loadProto(proto);
var clazz:any = builder.build("Common"); var data: any = clazz.decode(msgBuff);
console.log("decodeData id=" + data.get("id"));
console.log("decodeData oops=" + data.get("text"));

项目示例:下载

最后,感谢董刚同学提供的protobuf库。

深入了解使用egret.WebSocket的更多相关文章

  1. 【咸鱼教程】protobuf在websocket通讯中的使用

    教程目录一 protobuf简介二 使用protobuf三 Demo下载 参考: CSDN:Egret项目中使用protobuf(protobufjs) TS项目中使用Protobuf的解决方案(ba ...

  2. 网络游戏开发-客户端2(自定义websocket协议格式)

    Egret官方提供了一个Websocket的库,可以让我们方便的和服务器长连接交互. 标题写的时候自定义websocket的协议格式.解释一下,不是说我们去动websocket本身的东西,我们是在we ...

  3. 【Egret】WebSocket 的使用说明

    在Egret里可以使用WebSocket ,也可以使用socket.io 首先先深入了解一下 WebSocket 在Egret里的机制,看这篇文章: 主要讲解Egret里使用WebSocket和pro ...

  4. Pomelo实现最简单的通信-egret。

    昨天因为需要开始学习Pomelo 做H5游戏的服务端. 因为个人学习习惯,我从来不适合去跟着文档看.一般我直接是看下大概的API,但是Pomelo的API全部都是英文的. 昨天我就告诉自己用一下午时间 ...

  5. egret随笔-egret浅入浅出

    •不知道有多人跟笔者一样,喜欢学各种技术,但是都不精,但也有一两项算是精的. 自从踏上了egret游戏开发的道路,就不得不学习各种技术了,因为,要精通egret,首先必须要会TypeScript,其次 ...

  6. Egret入门了解

    0.前言 这个星期没有什么事做,就想找点技术了解一下.前段时间看过Egret,用来开发HTML5小游戏.一开始以为很麻烦的,但是经过这两天了解了一下,如果用这个游戏引擎来开发一些简单的游戏,还是蛮方便 ...

  7. egret游戏入门之学习资源篇

    最近因需要,入手H5游戏. 写游戏当然需要有引擎. H5游戏开发:游戏引擎入门推荐 如何选择 H5 游戏引擎 白鹭引擎和layabox哪个好用,哪个技术更成熟 ? LayaBox 与 Egret 选择 ...

  8. 浅谈白鹭Egret

    浅谈白鹭Egret           最近在做一个移动项目,技术选型的时候接触到了白鹭,简单了解了之后觉得挺合适的,最终就选择了这个引擎. 为什么会选择白鹭引擎呢? 我看上他主要有一下几点:   1 ...

  9. [egret+pomelo]实时游戏杂记(3)

    [egret+pomelo]学习笔记(1) [egret+pomelo]学习笔记(2) [egret+pomelo]学习笔记(3) 服务端的请求流程走完了一遍,下面就该看一下,在目前的服务端中,各服务 ...

随机推荐

  1. 数据结构(线段树):CodeForces 85D Sum of Medians

    D. Sum of Medians time limit per test 3 seconds memory limit per test 256 megabytes input standard i ...

  2. 【模拟】NCPC 2014 K Train passengers

    题目链接: http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1797 题目大意: 有N个车站,火车一共可以坐M个人,每个车站下车Ai,上车Bi个人,在 ...

  3. linux下安装python linux下一些常用的命令

    注意 ubuntukylin-14.04.2-desktop-amd64 自带python2.7.6 这个说的比较详细 http://wenku.baidu.com/link?url=gaeFcQrc ...

  4. 《A First Course in Probability》-chaper4-离散型随机变量-负二项分布

    基于我们最为熟悉的离散型分布——二项分布,我们能够衍生出很多别的分布列,对于之前介绍过的几何分布,我们赋予其的含义是:某个事件成功的概率是p,在n次独立重复实验中恰好成功一次的概率是多少.顺着这层含义 ...

  5. C++ sizeof

    class A{ int a; char c; char b; }; class B{ char c; int a; char b; }; int main(int argc, char* argv[ ...

  6. 每个项目单独配置 git 用户

    git多账号登陆问题 设置git全局设置: git config --global user.name "your_name"  git config --global user. ...

  7. 【BZOJ4327】JSOI2012 玄武密码 AC自动机

    [BZOJ4327]JSOI2012 玄武密码 Description 在美丽的玄武湖畔,鸡鸣寺边,鸡笼山前,有一块富饶而秀美的土地,人们唤作进香河.相传一日,一缕紫气从天而至,只一瞬间便消失在了进香 ...

  8. jquery常用见的正则表达式

    quickexpr = /^(?:[^<]*(<[ww]+>)[^>]*$|#([w-]+)$)/  (?:…)表示是一个非捕获型 [^<]表示是以"<& ...

  9. 统计学习导论:基于R应用——第四章习题

    第四章习题,部分题目未给出答案 1. 这个题比较简单,有高中生推导水平的应该不难. 2~3证明题,略 4. (a) 这个问题问我略困惑,答案怎么直接写出来了,难道不是10%么 (b) 这个答案是(0. ...

  10. CSS控制LI行字符溢出用省略号取代

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...