Websocek笔记二 搭建egret序列化字节流传输环境
此博客还未完善,需要加上很多解释文字
egret中的websocket有两种传输方式:
以二进制方式传输:
this.webSocket.type = egret.WebSocket.TYPE_BINARY;
以字符串形式传输:(this.webSocket.writeUTF(“abcde”);)
this.webSocket.type = egret.WebSocket.TYPE_STRING;
搭建字节流传输环境
源代码见我的上传资源
skynet服务端代码:
必须先搭建好skynet的websocket引用
字节流传输lua脚本代码:
skynet/test/testwebsocket.lua
local skynet = require "skynet"
local socket = require "skynet.socket"
local websocket = require "websocket"
local httpd = require "http.httpd"
local urllib = require "http.url"
local sockethelper = require "http.sockethelper"
local handler = {}
function handler.on_open(ws)
print(string.format("%d::open", ws.id))
--register Timer
skynet.fork(function()
while true do
-- ws:send_text("heart" .. "from server")
local string = "1212fdsafa";
local x = string.pack("IHHibIIII",0,1150,0,0,"4",1000,1001,1002,1003);
-- local y = {string.unpack('iii',x)};
ws:send_binary(x)
skynet.sleep(500)
end
end)
end
function handler.on_message(ws, message)
print(string.format("%d receive:%s", ws.id, message))
ws:send_binary("from server")
-- ws:close()
end
function handler.on_close(ws, code, reason)
print(string.format("%d close:%s %s", ws.id, code, reason))
end
local function handle_socket(id)
-- limit request body size to 8192 (you can pass nil to unlimit)
local code, url, method, header, body = httpd.read_request(sockethelper.readfunc(id), 8192)
if code then
if header.upgrade == "websocket" then
local ws = websocket.new(id, header, handler)
ws:start()
end
end
end
skynet.start(function()
local address = "0.0.0.0:8001"
skynet.error("Listening "..address)
local id = assert(socket.listen(address))
socket.start(id , function(id, addr)
socket.start(id)
pcall(handle_socket, id)
end)
end)
其中最关键的代码:
function handler.on_open(ws)中的:
local x = string.pack("IHHibIIII",0,1150,0,0,"4",1000,1001,1002,1003);//按照字符串中的顺序,把后面的n个参数序列化
ws:send_binary(x)
lua5.3中string.pack可以把数据序列化,格式:
#define OP_ZSTRING 'z' //空字符串
#define OP_BSTRING 'p' //长度小于2^8的字符串
#define OP_WSTRING 'P' //长度小于2^16的字符串
#define OP_SSTRING 'a' //长度小于2^32/64的字符串*/
#define OP_STRING 'A' //指定长度字符串
#define OP_FLOAT 'f' /* float */
#define OP_DOUBLE 'd' /* double */
#define OP_NUMBER 'n' /* Lua number */
#define OP_CHAR 'c' /* char */
#define OP_BYTE 'b' /* byte = unsigned char */
#define OP_SHORT 'h' /* short */
#define OP_USHORT 'H' /* unsigned short */
#define OP_INT 'i' /* int */
#define OP_UINT 'I' /* unsigned int */
#define OP_LONG 'l' /* long */
#define OP_ULONG 'L' /* unsigned long */
灵活自定义"IHHibllll" 序列化方式fmt,以及后面参数的方法
序列化的时候,参数填成一个函数
-- hello.lua
-- the first program in every language
function fun()
return 1,2,3,4,5,6,7
end
local x = string.pack('iii',fun());
local y = {string.unpack('iii',x)};
io.write("--",x,"--",y[1],y[2],y[3])
在线测试lua代码:
注意:本例中byte的fmt,egret项目Eprotocal中byte是“C”,服务端Lua代码byte中是“b”,拥有不同编码。所以本例中服务端的序列化码fmt("IHHibIIII"),和客户端的解序列化fmt码("IHHiCIIII")稍有不同。
本例的模拟数据,开头有四个信息是不属于数据内容
服务端模拟数据的格式
unsignedInt msgLen //这个的长度可以用断点,在CustomSocket.ts中的msgLen中查看
unsignedShort msg_type //协议类型,这个东西是根据它获取相应的协议class
unsignedShort msg_sid
Int msg_id
客户端代码
目录:
src/bytesArray/CustomByteArray.ts:
class CustomByteArray extends egret.ByteArray{
public constructor() {
super();
// this.endian = egret.Endian.BIG_ENDIAN;
this.endian = egret.Endian.LITTLE_ENDIAN;
}
public writeUTFBytes(str:string, len:number = 0):void{
if(len > 0){
for(let i:number = 0; i < len; i++){
this.writeByte(0);
}
}
let temp:number = this.position;
this.position -= len;
super.writeUTFBytes(str);
this.position = temp;
}
public readUTFBytes(len:number):string
{
let ba:egret.ByteArray = new egret.ByteArray()
ba.endian = egret.Endian.LITTLE_ENDIAN;
this.readBytes(ba, 0, len);
let res:string = ba.readUTFBytes(len);
ba.length = 0
ba = null
return res;
}
}
src/bytesArray/CustomSocket.ts:
class CustomSocket extends egret.EventDispatcher {
public static ERROR: string = "socket_error";
public static CONNECT: string = "socket_connect";
private _cmdArray: Array<Array<any>>;
private _thisArray: Array<Array<any>>;
private _bufferDataArray: Array<any>;
private _cashBytes: CustomByteArray;
private _contentLen: number = 0;
/** 协议头长度 (协议长度4 + 消息号2 + msg_sid2 + msg_id 4) */
private HEADLENGTH: number = 12;
private _readDataFlag: boolean = false;
public ip: string;
public port: number;
// public isClosed: boolean = true;
public get isClosed():boolean{
if(this._socket){
return !this._socket.connected;
}
return true;
}
private static _instance: CustomSocket;
public stopReceiveMsg:boolean = false;
public static getInstance(): CustomSocket {
if (CustomSocket._instance == null) {
CustomSocket._instance = new CustomSocket();
}
return CustomSocket._instance;
}
private _socket:MySocket;
public constructor() {
super();
this.init();
}
private init(): void {
this._cmdArray = new Array();
this._thisArray = new Array();
}
private reset():void{
if(this._bufferDataArray)
this._bufferDataArray.length = 0;
this._readDataFlag = false;
this._bufferDataArray = new Array();
}
public get id():number{
if(this._socket == null){
return 0;
}
return this._socket.id;
}
//开始连接
private _connFailed:boolean = false;
public connecting:boolean = false;
public start(ip: string = null, port: number = 0): void {
this.ip = ip;
this.port = port;
if(this._socket == null){
this._socket = new MySocket();
this.configureListeners();
}
this.reset();
this._connFailed = false;
this.connecting = true;
send_msg_num = 0;
rec_msg_num = 0;
if (useSSL) {
let url:string = `wss://${ip}`;
trace(`[CustomSocket:start][${this.id}] url=${url}`);
this._socket.connectByUrl(url);
}
else {
trace(`[CustomSocket:start][${this.id}] [host=${this.ip} port=${this.port} id=${this._socket.id} time=${NOWTIMER}]`);
if(this.ip.indexOf("s-") == 0){
let tarr:string[] = this.ip.split("/");
if(tarr.length == 2){
this.ip = tarr[0].replace("s-", tarr[1]+"-");
}
}else{
let reg:RegExp = new RegExp("x\d+\-", "i");
let strarr = this.ip.match(reg);
if(strarr && strarr.length > 0){
let tarr:string[] = this.ip.split("/");
if(tarr.length == 2){
this.ip = tarr[0].replace(reg, tarr[1]+"-");
}
}
}
this._socket.connect(this.ip, this.port);
}
}
public close():void{
trace(`[CustomSocket:close][${this.id}][主动]关闭连接!!${this.isClosed} time=${NOWTIMER}`);
// this.removeListeners();
// this.isClosed = true;
// this._socket = null;
this.connecting = false;
this._socket.close();
}
// private removeListeners():void{
// if(this._socket){
// this._socket.removeEventListener(egret.Event.CLOSE, this.closeHandler, this);
// this._socket.removeEventListener(egret.Event.CONNECT, this.connectHandler, this);
// this._socket.removeEventListener(egret.IOErrorEvent.IO_ERROR, this.ioErrorHandler, this);
// this._socket.removeEventListener(egret.ProgressEvent.SOCKET_DATA, this.socketDataHandler, this);
// // this._socket.close();
// }
// }
//配置socket监听事件
private configureListeners(): void {
this._socket.addEventListener(egret.Event.CLOSE, this.closeHandler, this);
this._socket.addEventListener(egret.Event.CONNECT, this.connectHandler, this);
this._socket.addEventListener(egret.IOErrorEvent.IO_ERROR, this.ioErrorHandler, this);
this._socket.addEventListener(egret.ProgressEvent.SOCKET_DATA, this.socketDataHandler, this);
}
private connectHandler(event: egret.Event): void {
let sk:MySocket = event.currentTarget as MySocket;
trace(`-----------------连接成功--------------${sk.id}/${this._socket.id}`);
// if(this._socket.id != sk.id)
// return;
// this.isClosed = false;
this.connecting = false;
this.dispatchEvent(new ParamEvent(CustomSocket.CONNECT));
}
//IO错误
private ioErrorHandler(event: egret.Event): void {
let sk:MySocket = event.currentTarget as MySocket;
trace(`----------------err网络故障----------------${sk.id}/${this._socket.id}/${this._connFailed}::::::${this._socket.connected}`);
// if(this._socket.id != sk.id)
// return;
this.connecting = false;
if(!this._connFailed){
this._connFailed = true;
}else{
return;
}
// if(!this.isClosed){
// this.isClosed = true;
if(this._socket.connected){
// this.close();
this._socket.close();
}
this.dispatchEvent(new ParamEvent(CustomSocket.ERROR, { code: 2 }));
// }
}
//服务端断开连接
private closeHandler(event: egret.Event): void {
let sk:MySocket = event.currentTarget as MySocket;
trace(`--------------socket断开了---------------${sk.id}/${this._socket.id}/${this._connFailed}::::::${this._socket.connected}`);
// if(this._socket.id != sk.id)
// return;
this.connecting = false;
if(!this._connFailed){
this._connFailed = true;
}else{
return;
}
// if(!this.isClosed){
// this.isClosed = true;
if(this._socket.connected){
// this.close();
this._socket.close();
}
this.dispatchEvent(new ParamEvent(CustomSocket.ERROR, { code: 1 }));
// }
}
//收到socket数据进行处理
private socketDataHandler(event: ProgressEvent): void {
LAST_SOCKET_TIME = NOWTIMER;
var bytes: CustomByteArray = new CustomByteArray(); //开辟缓冲区
this._socket.readBytes(bytes); //将数据读入内存缓冲区
this._bufferDataArray.push(bytes);
if (!this._readDataFlag) //如果当前没有在数据处理中 将开始处理数据,否则等待处理
{
this._readDataFlag = true; //设置状态标志为处理中
this.handleBufferData(); //开始处理数据·
this._readDataFlag = false;
}
event = null;
bytes = null;
}
//处理缓冲区数据
private handleBufferData(): void {
if (this._bufferDataArray.length <= 0) {
//当前数据缓冲区为空
this._readDataFlag = false;
return;
}
//如果不为空 将读取队列头数据
var bytesArray: CustomByteArray = this._bufferDataArray.shift();
bytesArray.position = 0; //将字节数组指针还原
//如果上一次缓存的字节数组里面有东西,将读取出来和这一次进行拼接
if (this._cashBytes != null && this._cashBytes.bytesAvailable > 0) {
var dataBytes: CustomByteArray = new CustomByteArray();
this._cashBytes.readBytes(dataBytes, 0, this._cashBytes.bytesAvailable);
bytesArray.readBytes(dataBytes, dataBytes.length, bytesArray.bytesAvailable);
this._cashBytes = null;
bytesArray = dataBytes;
bytesArray.position = 0; //将字节数组指针还原
dataBytes = null;
}
if (this._contentLen == 0 && bytesArray.bytesAvailable < this.HEADLENGTH) {
//当前数据不够一条最短协议的长度,且还未读取过包长度 将缓存数据
this.cacheRemainBytes(bytesArray);
bytesArray.length = 0;
bytesArray = null;
this.handleBufferData(); //重新开始去队列数据
}
else {
//将字节数组转换成数据
this.getBytes(bytesArray);
dataBytes = null;
bytesArray = null;
}
}
// 将 ba 读取之后剩余的数据放入缓冲区,等待下一次消息触发时拼接
private cacheRemainBytes(ba:CustomByteArray):void{
if(this._cashBytes == null)
this._cashBytes = new CustomByteArray();
ba.readBytes(this._cashBytes, this._cashBytes.length, ba.bytesAvailable);
ba = null;
}
public getBytes(bytesArray: CustomByteArray): void {
let msgLen:number = 0; // 协议长度
if(bytesArray.bytesAvailable < 4){ // 小于4字节,不够读取长度
this.cacheRemainBytes(bytesArray);
bytesArray.length = 0;
bytesArray = null;
this.handleBufferData(); // 继续读取消息队列
}else{
msgLen = bytesArray.readUnsignedInt();
if(bytesArray.bytesAvailable < msgLen){ // 剩下的字节不够一个协议长度了
// 因为已经读取了4字节的长度了,要将剩余的加入到缓冲区里面,这时指针要回退4个字节
bytesArray.position -= 4;
this.cacheRemainBytes(bytesArray);
bytesArray.length = 0;
bytesArray = null;
this.handleBufferData(); // 继续读取消息队列
}else{
// 读取协议内容
let msgBytes:CustomByteArray = new CustomByteArray();
bytesArray.readBytes(msgBytes, 0, msgLen);
// 读取到协议,进行处理
this.getMsgBytes(msgBytes);
msgBytes = null;
// 如果还有数据继续读取
if(bytesArray.bytesAvailable > 0){
this.getBytes(bytesArray)
bytesArray = null;
}else{
bytesArray.length = 0;
bytesArray = null;
this.handleBufferData();
}
}
}
}
/** 在主角信息获取到之前,除了登录+心跳+角色基础+角色列表信息,其他的协议先缓存起来 */
private _waitProtoList:any[] = [];
private getMsgBytes(msgBytes:CustomByteArray):void{
let proto:EProtocol = EProtocol.parseProtocol(msgBytes);
if(proto == null || this.stopReceiveMsg){
return;
}
let cmd:number = proto.msg_type;
// console.log(`收到消息::${cmd}`);
if(!MAINROLE_DATA_INITED){
if(cmd > 1000 && cmd != 2700 && cmd != 2703){
this._waitProtoList.push(proto);
}else{
this.dispatchProtocol(proto);
if(cmd == 2703){
MAINROLE_DATA_INITED = true;
// 收到角色列表信息,表示角色数据初始化完成,清空等待队列里的协议
for(let i:number = 0; i < this._waitProtoList.length; i++){
let e:EProtocol = this._waitProtoList[i];
this.dispatchProtocol(e);
}
}
}
return;
}
this.dispatchProtocol(proto);
rec_msg_num++;
}
public dispatchProtocol(proto:EProtocol):void{
let cmd:number = proto.msg_type;
let hander: Array<any> = this._cmdArray[cmd];
let thisarr: Array<any> = this._thisArray[cmd];
if (hander == null || hander.length <= 0) {
console.log(`协议 ${cmd} 没有被侦听`)
return;
}
for (let i: number = 0; i < hander.length; i++) {
// hander[i](proto)
hander[i].apply(thisarr[i], [proto]); // dxy 20180110 没有实现this很蛋疼
}
hander = null;
thisarr = null;
}
/** 清理因为没有登录成功而等待的消息 */
public clearWaitMsg():void{
while(this._sendWaitMsg.length > 0){
let proto:EProtocol = this._sendWaitMsg.shift();
this.sendMessage(proto);
}
}
private _sendWaitMsg:EProtocol[] = [];
public sendMessage(proto:EProtocol):void{
if(this.isClosed){
// if(!this.connecting && !GameCtrl.ins.connPoped && proto.msg_type > 109){
// GameCtrl.ins.connTimeout("网络连接断开,请点击确定重试!");
// }
return;
}
if(proto.msg_type > 103 && !hadLogined){
console.log(`协议[${proto.msg_type}]需要在登录成功后才能发送!!`)
this._sendWaitMsg[this._sendWaitMsg.length] = proto;
return;
}
LAST_SEND_MSG_TIME = NOWTIMER;
let ba:CustomByteArray = EProtocol.packProtocol(proto);
// console.log(`[sendMessage]::${proto.msg_type},len=${ba.length}`)
if(ba){
this._socket.writeBytes(ba);
this._socket.flush();
ba.length = 0;
ba = null;
send_msg_num++;
}
}
/**
*添加某个消息号的监听
* @param cmd 消息号
* @param args 传两个参数,0为处理函数 1为需要填充的数据对象
*
*/
addCmdListener(cmd: number, hander: Function, thisObj: any): void {
if (this._cmdArray[cmd] == null) {
this._cmdArray[cmd] = [];
this._thisArray[cmd] = [];
}
if (this._cmdArray[cmd].indexOf(hander) == -1) {
this._cmdArray[cmd].push(hander);
this._thisArray[cmd].push(thisObj);
}
}
/**
*移除 消息号监听
* @param cmd
*
*/
removeCmdListener(cmd: number, listener: Function): void {
var handers: any[] = this._cmdArray[cmd];
var thisarr: any[] = this._thisArray[cmd];
if (handers != null && handers.length > 0) {
for (var i: number = (handers.length - 1); i >= 0; i--) {
if (listener == handers[i]) {
handers.splice(i, 1);
thisarr.splice(i, 1);
}
}
}
}
}
src/bytesArray/EProtocol.ts
/**
* 协议基类
*
*/
class EProtocol {
/**
* 根据协议号,创建对应协议的实例
*/
public static createProtocol(msg_type:number):any{
let cls = ProtocolMap[msg_type];
if(cls)
return new cls(msg_type);
else{
console.log(`未注册的协议号${msg_type}`)
return null;
}
}
/**
* 解析协议
*/
public static parseProtocol(bytes:CustomByteArray):EProtocol{
let msg_type:number = bytes.readUnsignedShort();
let msg_sid:number = bytes.readUnsignedShort();
let msg_id:number = bytes.readInt();
let proto:EProtocol = EProtocol.createProtocol(msg_type) as EProtocol;
if(proto){
proto.msg_sid = msg_sid;
proto.msg_id = msg_id;
proto.protoBytes = bytes;
proto.decode();
}
bytes.length = 0;
bytes = null;
return proto;
}
/**
* 封装协议
*/
public static packProtocol(proto:EProtocol):CustomByteArray{
proto.encode();
if(proto.protoBytes == null)
{
console.log("协议内容为空")
return null;
}
let len:number = proto.protoBytes.length; // 协议长度
let bytes = new CustomByteArray();
bytes.writeUnsignedInt(len);
// proto.protoBytes.position = 0;
bytes.writeBytes(proto.protoBytes, 0, len);
return bytes;
}
public msg_type:number;
public msg_sid:number;
public msg_id:number;
private _bytes:CustomByteArray;
public constructor(msg_type:number, msg_sid?:number) {
this.msg_type = msg_type;
this.msg_sid = msg_sid == null ? -1 : msg_sid;
this.msg_id = 0;
}
public set protoBytes(bytes:CustomByteArray){
this._bytes = bytes;
}
public get protoBytes():CustomByteArray{
return this._bytes;
}
private dispose():void{
this._bytes.position = 0;
this._bytes = null;
}
protected writeFMT(format, ...params):boolean{
let ba:CustomByteArray = this._bytes;
if(ba == null){
console.log("writeFMT 没有设置协议数据");
return false;
}
let len = format.length;
let i:number;
let idx:number = 0
for(i = 0; i < len; i++){
let t = format.charAt(i);
let v = params[idx++];
if(v == null){
this.dispose();
console.log("format格式与对应参数不匹配")
return false;
}
let charnum = 0;
let isstr:boolean = false;
switch(t){
case 'i': { ba.writeInt(v); break; }
case 'I': { ba.writeUnsignedInt(v); break; }
case 'd': { ba.writeDouble(v); break; }
case 'h': { ba.writeShort(v); break; }
case 'H': { ba.writeUnsignedShort(v); break; }
case 'c': { ba.writeByte(v); break; }
case 'C': { ba.writeByte(v); break; }
case 'f': { ba.writeFloat(v); break; }
case 's': {
isstr = true;
let j = i + 1;
let numstr:string = "";
while(j < len){
let chr:number = format.charCodeAt(j);
if(chr >= 48 && chr <= 58){
numstr += format.charAt(j);
i++;
j++;
}else{
break;
}
}
if(numstr != "")
charnum = Number(numstr);
break;
}
default:{
this.dispose()
console.log("不是正确的格式:" + t);
return false;
}
}
if(isstr){
if(charnum > 0){
ba.writeUTFBytes(v, charnum);
}else{
this.dispose();
console.log("format中s没有设定长度!");
return false;
}
}
}
if(idx != params.length){
this.dispose();
console.log(`format定义与参数个数不匹配${idx}/${params.length}`);
}
return true;
}
protected readFMT(format:string):any[]{
let ba:CustomByteArray = this._bytes;
if(ba == null){
console.log("readFMT 没有设置协议数据");
return null;
}
let res:any[] = [];
let len = format.length;
let i:number;
for(i = 0; i < len; i++){
let t = format.charAt(i);
let charnum = 0;
let val;
let isstr:boolean = false;
switch(t){
case 'i': { val = ba.readInt(); break; }
case 'I': { val = ba.readUnsignedInt(); break; }
case 'd': { val = ba.readDouble(); break; }
case 'h': { val = ba.readShort(); break; }
case 'H': { val = ba.readUnsignedShort(); break; }
case 'c': { val = ba.readByte(); break; }
case 'C': { val = ba.readUnsignedByte(); break; }
case 'f': { val = ba.readFloat(); break; }
case 's': {
isstr = true;
let j = i + 1;
let numstr:string = "";
while(j < len){
let chr:number = format.charCodeAt(j);
if(chr >= 48 && chr <= 58){
numstr += format.charAt(j);
i++;
j++;
}else{
break;
}
}
if(numstr != "")
charnum = Number(numstr);
break;
}
default:{
this.dispose()
console.log("不是正确的格式:" + t);
}
}
if(isstr){
if(charnum > 0){
val = ba.readUTFBytes(charnum);
}else{
this.dispose();
console.log("format中s没有设定长度!");
}
}
res.push(val);
}
return res;
}
public encode():void{
// 添加协议头
this._bytes = new CustomByteArray();
this._bytes.writeUnsignedShort(this.msg_type);
this._bytes.writeUnsignedShort(this.msg_sid);
this._bytes.writeInt(this.msg_id);
}
public decode():void{
}
}
src/bytesArray/Globals.ts
/** 协议字典 */
var ProtocolMap:{[msg_type:number]:any} = {};
var send_msg_num = 0;
var rec_msg_num = 0;
var useSSL:boolean = false;
/** 已经登录(服务器返回登录成功,在这之前,只有 登录/创角 协议可以发送) */
var hadLogined:boolean = false;
function trace(...args):void{
let dt:Date = new Date();
let str:string = `[${dt.getHours()}:${dt.getMinutes()}:${dt.getSeconds()}]`;
// args.unshift(str);
// console.log.apply(null, args);
// console.log.call(null, str, ...args);
for(let i=0; i<arguments.length; i++){
str += `${arguments[i]} `;
}
console.log(str);
}
/** 启动到当前的时间(ms) */
var NOWTIMER:number = 0;
/** 最后收到服务器消息的时间(用来做心跳超时) */
var LAST_SOCKET_TIME:number = 0;
/** 最后发送消息时间 */
var LAST_SEND_MSG_TIME:number = 0;
var MAINROLE_DATA_INITED:boolean = true;
class EMsgCode {
public static SC_GuildWarTime = 1150;
}
src/bytesArray/msg_test.ts
class SC_GuildWarTime extends EProtocol {
public time_arr: Array<number> = [];
public constructor(msg_sid: number) {
super(EMsgCode.SC_GuildWarTime, msg_sid);
}
public decode(): void {
let count = this.readFMT("C")[0];
for (var i = 0; i < count; i++) {
let arr = this.readFMT("I")
this.time_arr.push(arr[0])
}
}
}
ProtocolMap[EMsgCode.SC_GuildWarTime] = SC_GuildWarTime;
src/bytesArray/MySocket.ts
class MySocket extends egret.WebSocket {
public ip: string;
public port: number;
public isClosed: boolean = true;
private _id:number;
private static NET_INDEX:number = 0;
public get id():number{
return this._id;
}
public constructor() {
super();
this._id = ++MySocket.NET_INDEX;
this.type = egret.WebSocket.TYPE_BINARY;
}
// private removeEvent():void{
// this.addEventListener(egret.Event.CLOSE, this.closeHandler, this);
// this.addEventListener(egret.Event.CONNECT, this.connectHandler, this);
// this.addEventListener(egret.IOErrorEvent.IO_ERROR, this.ioErrorHandler, this);
// this.addEventListener(egret.ProgressEvent.SOCKET_DATA, this.socketDataHandler, this);
// }
// private addEvent():void{
// this.removeEvent();
// this.removeEventListener(egret.Event.CLOSE, this.closeHandler, this);
// this.removeEventListener(egret.Event.CONNECT, this.connectHandler, this);
// this.removeEventListener(egret.IOErrorEvent.IO_ERROR, this.ioErrorHandler, this);
// this.removeEventListener(egret.ProgressEvent.SOCKET_DATA, this.socketDataHandler, this);
// }
// //IO错误
// private ioErrorHandler(event: egret.Event): void {
// if(!this.isClosed){
// this.isClosed = true;
// console.log("----------------------服务器重启了-------------------");
// this.dispatchEvent(new ParamEvent(CustomSocket.ERROR, { code: 2 }));
// }
// }
// //判断是否在连接中
// private connectHandler(event: egret.Event): void {
// console.log("---------------------连接成功------------------");
// this.isClosed = false;
// this.dispatchEvent(new ParamEvent(CustomSocket.CONNECT));
// }
// //服务端断开连接
// private closeHandler(event: egret.Event): void {
// if(!this.isClosed){
// this.isClosed = true;
// console.log("----------------------socket断开了-------------------");
// this.dispatchEvent(new ParamEvent(CustomSocket.ERROR, { code: 1 }));
// }
// }
// //收到socket数据进行处理
// private socketDataHandler(event: ProgressEvent): void {
// LAST_SOCKET_TIME = NOWTIMER;
// var bytes: CustomByteArray = new CustomByteArray(); //开辟缓冲区
// this.readBytes(bytes); //将数据读入内存缓冲区
// this._bufferDataArray.push(bytes);
// if (!this._readDataFlag) //如果当前没有在数据处理中 将开始处理数据,否则等待处理
// {
// this._readDataFlag = true; //设置状态标志为处理中
// this.handleBufferData(); //开始处理数据·
// this._readDataFlag = false;
// }
// event = null;
// bytes = null;
// }
}
src/bytesArray/ParamEvent.ts
class ParamEvent extends egret.Event{
public data:any;
public constructor(type:string, data:any=null) {
super(type);
this.data = data;
}
}
src/Controller/BaseContol.ts
class BaseContol {
protected _dispatcher: GameEvent;
protected _socket: CustomSocket;
/** -1:立即执行 0:500-1500ms随机执行 >0:指定延迟时间执行 */
protected _callBackDelay: number = 0;
public constructor() {
this.init();
this.addEventHandler();
this.addCmdHandler();
}
protected init(): void {
this._socket = CustomSocket.getInstance();
this._dispatcher = GameEvent.ins;
// this.addEventListener(EventName.GAME_START, this.whenGameStart, this);
// this.addEventListener(EventName.GAME_RE_START, this.onRestart, this);
}
// protected whenGameStart(e:ParamEvent):void{
// this.removeEventListener(EventName.GAME_START, this.whenGameStart, this, false);
// var delay: number = this._callBackDelay;
// if (delay == -1) {
// this.onGameStart();
// return;
// }
// if (delay == 0) {
// delay = 500 + Math.ceil(Math.random() * 1000) >> 1;
// }
// setTimeout2(() => {
// // let tm = NOWTIMER;
// this.onGameStart();
// }, delay);
// }
// protected onRestart(event:ParamEvent):void{
// }
protected onGameStart(event?: ParamEvent): void {
}
protected addCmdHandler(): void { }
protected addEventHandler(): void {
}
protected addCmdListener(cmd: number, fun: Function, thisObj: any): void {
this._socket.addCmdListener(cmd, fun, thisObj);
}
protected removeCmdListener(cmd: number, fun: Function): void {
}
protected sendSocketData(cmd: number, data: Object = null): void {
// this._socket.sendMessage(cmd, data);
}
protected addEventListener(eventName: string, func: Function, thisObj: any, useCapture: boolean = false, priority: number = 1): void {
this._dispatcher.addEventListener(eventName, func, thisObj, useCapture, priority);
}
protected removeEventListener(eventName: string, func: Function, thisObj: any, useCapture: boolean = false): void {
this._dispatcher.removeEventListener(eventName, func, thisObj, useCapture);
}
protected hasEventListener(eventName: string): boolean {
return this._dispatcher.hasEventListener(eventName);
}
protected once(eventName: string, func: Function, thisObj: any, useCapture: boolean = false): void {
this._dispatcher.once(eventName, func, thisObj, useCapture)
}
protected dispatchEvent(event: egret.Event): boolean {
return this._dispatcher.dispatchEvent(event);
}
protected willTrigger(eventName: string): boolean {
return this._dispatcher.willTrigger(eventName);
}
}
src/Controller/GameCtrl.ts
注意这个地方,要在虚拟机查看本机Ip,中找到skynet的服务器地址,还有skynet/examples/config找到监听端口
class GameCtrl extends BaseContol {
private _host: string = "192.168.137.151";//这里填入虚拟机服务器的ip地址
private _port: number = 8001; //这里填skynet的网络端口
public constructor() {
super();
this._socket.start(this._host, this._port);
}
private static _instance: GameCtrl;
public static get ins(): GameCtrl {
if (GameCtrl._instance == null)
GameCtrl._instance = new GameCtrl();
return GameCtrl._instance;
}
protected addCmdHandler(): void {
this._socket.addCmdListener(EMsgCode.SC_GuildWarTime, this.SSC_GuildWarTime, this);
}
/**
* 返回协议内容
* @param e 返回的协议内容
*/
private SSC_GuildWarTime(e: EProtocol):void{
let message: SC_GuildWarTime = e as SC_GuildWarTime;
console.log("SC_GuildWarTime = 1147 时间列表变更返回:", message);
}
}
src/Controller/GameEvent.ts
class GameEvent extends egret.EventDispatcher {
private static _instance: GameEvent;
public constructor() {
super();
}
public static get ins(): GameEvent {
if (GameEvent._instance == null) {
GameEvent._instance = new GameEvent();
}
return GameEvent._instance;
}
public addEvent(eventName: string, func: Function, thisObj: any, useCapture: boolean = false, priority: number = 1): void {
super.addEventListener(eventName, func, thisObj, useCapture, priority);
}
public removeEvent(eventName: string, func: Function, thisObj: any, useCapture: boolean = false): void {
super.removeEventListener(eventName, func, thisObj, useCapture);
}
public hasEvent(eventName: string): boolean {
return super.hasEventListener(eventName);
}
public once(eventName: string, func: Function, thisObj: any, useCapture: boolean = false): void {
super.once(eventName, func, thisObj, useCapture)
}
public dispatchEvent(event: egret.Event): boolean {
var t1: number = egret.getTimer();
var result: boolean = super.dispatchEvent(event);
var gap:number = egret.getTimer() - t1;
if (gap > 5) {
//console.log(StringUtil.substitute("send Evt gap = {1} name = {0}", event.type, gap));
}
return result;
}
public willTrigger(eventName: string): boolean {
return super.willTrigger(eventName);
}
}
在:Main.ts中:
private createGameScene() {
GameCtrl.ins;
}
运行测试:
每隔5s钟就会收到协议并解析