热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

使用cocoscreator+node.js+websocket实现简单的聊天服务

先上个效果图:使用cocoscreator1.9.1+node.js+websocket实现,没有使用socket.io,全部自己封装,长连接进行封装后可以和短连接使用方法一样,使

先上个效果图:

使用cocoscreator 1.9.1 + node.js + websocket实现,没有使用socket.io, 全部自己封装,长连接进行封装后可以和短连接使用方法一样,使用简单,方便以后开发网络游戏。

1、客户端:

  主要就是聊天内容的显示,自动换行和背景扩展,代码大概如下:

cc.Class({
    extends: cc.Component,

    properties: {
        msgLabel: cc.Label,
        uidLabel: cc.Label,
        msgLayout: cc.Layout,
        msgBg: cc.Node,
        maxLen: 500,
    },

    // LIFE-CYCLE CALLBACKS:

    // onLoad () {},

    start () {
        this.node.runAction(cc.fadeTo(0.5, 255))
    },

    initMsg(msg, uid){
        this.msgLabel.string = msg;
        this.uidLabel.string = uid;

        this.msgLabel.overflow = cc.Label.Overflow.NONE;
        // this.msgBg.width = this.msgLabel.node.width + 10;
        // this.msgBg.height = this.msgLabel.node.height + 10;
        // this.node.height = this.msgBg.height + 40;

        this.scheduleOnce((dt)=>{
            if ( this.msgLabel.node.width >= this.maxLen){
                this.msgLabel.overflow = cc.Label.Overflow.RESIZE_HEIGHT;
                this.msgLabel.node.width = this.maxLen;
            }

            this.msgBg.width = this.msgLabel.node.width + 10;
            this.msgBg.height = this.msgLabel.node.height + 10;
            this.node.height = this.msgBg.height + 40;

        }, 0);

        this.node.opacity = 0;
    }

    // update (dt) {},
});

  网络部分分成了四层:

    1、socket 封装基础的websocket, 这里是最底层,也是真正链接的开始

    2、network 控制socket链接层,实现各回调接口

    3、netproxy 封装各服务功能,把长连接变成短连接的请求方式

    4、netprotocols 和服务器协商,确定每个请求的请求体格式和回复格式

  各部分代码如下:

  GameWebSocket.js:  

/**
 * @enum {number}
 */
var GameWebSocketState = cc.Enum({
    CONNECTING: 1,
    OPEN: 2,
    CLOSING: 3,
    CLOSED: 4
});

/**
 * @interface
 */
var GameWebSocketDelegate = cc.Class({

    onSocketOpen: function () {

    },

    /**
     * 收到了消息
     * @param {string|Uint8Array} data
     */
    onSocketMessage: function (data) {

    },

    onSocketError: function () {

    },

    /**
     * 连接关闭
     * @param {string} reason
     */
    onSocketClosed: function (reason) {

    }
});

/**
 * @interface
 */
var GameWebSocketInterface = cc.Class({

    connect: function () {

    },

    send: function () {

    },

    close: function () {

    },

    getState: function () {

    }
});

var GameWebSocket = cc.Class({
    extends: GameWebSocketInterface,

    properties: {

        /**
         * @type {String} 服务器地址
         */
        _address: null,

        /**
         * @type {GameWebSocketDelegate}
         */
        _delegate: null,

        /**
         * @type {WebSocket}
         */
        _webSocket: null,
    },

    /**
     * @param {string} address 服务器地址
     * @param {GameWebSocketDelegate} delegate 回调接口
     */
    init: function(address, delegate){
        this._address = address;
        this._delegate = delegate;
        this._webSocket = null;
    },

    connect: function () {
        cc.log('connect to '+ this._address);

        var ws = this._webSocket = new WebSocket(this._address);
        ws.onopen = this._delegate.onSocketOpen.bind(this._delegate);
        ws.onmessage = function (param) {
            this._delegate.onSocketMessage(param.data);
        }.bind(this);
        ws.onerror = this._delegate.onSocketError.bind(this._delegate);
        // function({code: Number, reason: String, wasClean: Boolean})}
        ws.Onclose= function (param) {
            this._delegate.onSocketClosed(param.reason);
        }.bind(this);
    },

    /**
     * 发送数据
     * @param {string|Uint8Array} stringOrBinary
     */
    send: function (stringOrBinary) {
        this._webSocket.send(stringOrBinary);
    },

    close: function () {
        if (!this._webSocket) {
            return;
        }

        try {
            this._webSocket.close();
        } catch (err) {
            cc.log('error while closing webSocket', err.toString());
        }
        this._webSocket = null;
    },

    getState: function () {
        if (this._webSocket) {
            switch(this._webSocket.readyState){
                case WebSocket.OPEN:
                    return GameWebSocketState.OPEN;
                case WebSocket.CONNECTING:
                    return GameWebSocketState.CONNECTING;
                case WebSocket.CLOSING:
                    return GameWebSocketState.CLOSING;
                case WebSocket.CLOSED:
                    return GameWebSocketState.CLOSED;
            }
        }
        return GameWebSocketState.CLOSED;
    }
});

module.exports = {
    GameWebSocketState: GameWebSocketState,
    GameWebSocketDelegate: GameWebSocketDelegate,
    GameWebSocketInterface: GameWebSocketInterface,
    GameWebSocket: GameWebSocket
};

  GameNetwork.js

/**
 * Created by skyxu on 2018/10/9.
 */

"use strict";

let GameWebSocket = require("./GameWebSocket");
let GameProtocols = require("./GameProtocols");

/**
 * 服务器回复消息状态,判断回复消息的各种问题
 */
var response_state = {
    ERROR_OK : '0'
};

/**
 * 请求回调对象,收到服务器回调后的回调方法
 */
var NetworkCallback = cc.Class({

    properties: {

        /**
         * @type {BaseRequest} request
         */
        request: null,

        /**
         * 请求回调对方法
         */
        callback: null
    },

    /**
     * @param {BaseRequest} request
     * @param {function(BaseResponse): boolean} callback
     */
    init: function (request, callback) {
        this.request = request;
        this.callback = callback;
    }
});


let GameNetwork = cc.Class({
    extends: GameWebSocket.GameWebSocketDelegate,

    ctor: function() {
        this._socket = null;

        this._delegate = null;

        /**
         * 每次发送请求,都需要有一个唯一的编号
         * @type {number}
         * @private
         */
        this._requestSequenceId = 0;

        /**
         * 接受服务器主动下发的response回调
         * key 表示BaseResponse.act
         * @type {Object.)>}
         */
        this.pushRespOnseCallback= {};

        /**
         * 根据seq保存Request和其callback,以便在收到服务器的响应后回调
         * @type {Object.}
         * @private
         */
        this._networkCallbacks = {};
    },

    setDelegate: function (delegate) {
        this._delegate = delegate;
    },

    /**
     * 注册服务器主动推送的response 回调
     */
    registerPushResponseCallback : function(act, callback){
        this.pushResponseCallback[act] = callback;
    },

    /**
     * 判断socket已连接成功,可以通信
     * @returns {boolean}
     */
    isSocketOpened: function(){
        return (this._socket && this._socket.getState() == GameWebSocket.GameWebSocketState.OPEN);
    },

    isSocketClosed: function () {
        return this._socket == null;
    },

    /**
     * 启动连接
     */
    connect: function (url) {
        cc.log("webSocketUrls=" + url);
        this._requestSequenceId = 0;
        this._socket = new GameWebSocket.GameWebSocket();
        this._socket.init(url, this);
        this._socket.connect();
    },

    closeConnect: function () {
        if(this._socket){
            this._socket.close();
        }
    },

    onSocketOpen: function () {
        cc.log('Socket:onOpen');
        if(this._delegate && this._delegate.onNetworkOpen){
            this._delegate.onNetworkOpen();
        }
    },

    onSocketError: function () {
        cc.log('Socket:onError');
    },

    onSocketClosed: function (reason) {
        cc.log('Socket:onClose', reason);
        if (this._socket) {
            this._socket.close();
        }
        this._socket = null;

        if(this._delegate && this._delegate.onNetworkClose){
            this._delegate.onNetworkClose();
        }
    },

    onSocketMessage: function (msg) {
        this._onResponse(msg);
    },

    _onResponse: function(responseData){
        cc.log('response->resp:', responseData);
        var respOnseJson= JSON.parse(responseData);
        var respOnseClass= GameProtocols.response_classes[responseJson.act];
        /**
         * @type {object.}
         */
        var respOnse= new responseClass();
        response.loadData(responseJson.data);
        response.act = responseJson.act;
        response.seq = responseJson.seq;
        response.err = responseJson.err;
        response.ts = responseJson.ts;

        // 如果指定了回调函数,先回调
        var ignoreError = false;
        if(response.seq != -1){
            // 处理服务器推送消息
            var pushCallback = this.pushResponseCallback[response.act];
            if(pushCallback){
                pushCallback(response);
            }

            // request回调
            var callbackObj = this._networkCallbacks[response.seq];
            if(callbackObj){
                ignoreError = callbackObj.callback(response);
                // try {
                //     ignoreError = callbackObj.callback(response);
                // } catch (err) {
                //     cc.log(err + " error in response callback of " + response.act);
                // } finally {
                //     delete this._networkCallbacks[response.seq];
                // }
            }
        }

        //有错,且不忽略,则统一处理错误
        if(response.err && response.err != response_state.ERROR_OK && !ignoreError){
            if (response.is_async) {  // 异步请求,如果出错了,应该需要重新登录
                // todo 重新登录?或者重新同步数据?
            } else {  // 同步请求,如果出错了,需要显示错误信息
                // todo 显示错误
                var msg = responseJson.msg;
                cc.log('server err ' + msg);
            }
        }
    },

    /**
     * 向服务器发送请求。
     *
     * 如果提供了callback,在收到response后会被回调。如果response是一个错误(status!=ERR_OK),则需要决定由谁来负责处理错误。
     * 如果callback中已经对错误进行了处理,应该返回true,这样会忽略该错误。否则应该返回false,则负责处理该错误。
     *
     * 特别注意:如果这是一个异步(is_async)请求,且出错,一般来讲应该重新登录/同步。但是如果callback返回了true,不会进行
     * 任何处理,也就是不会重新登录/同步。请小心确定返回值。
     *
     * @param {object.}
     * @param {function(BaseResponse): boolean=} opt_callback 回调函数。出错的情况下,如果返回true,则不会再次处理错误。
     */
    sendRequest: function (request, opt_callback) {
        // 每个请求的seq应该唯一,且递增
        request.seq = ++this._requestSequenceId;

        //生成NetworkCallback对象,绑定请求seq和回调方法
        if(opt_callback){
            this._networkCallbacks[request.seq] = new NetworkCallback();
            this._networkCallbacks[request.seq].init(request, opt_callback);
        }
        this._sendSocketRequest(false, request);
    },

    /**
     * sendRequest的不发送data字段
     */
    sendRequestNoData: function (request, opt_callback) {
        // 每个请求的seq应该唯一,且递增
        request.seq = ++this._requestSequenceId;

        //生成NetworkCallback对象,绑定请求seq和回调方法
        if(opt_callback){
            this._networkCallbacks[request.seq] = new NetworkCallback();
            this._networkCallbacks[request.seq].init(request, opt_callback);
        }
        this._sendSocketRequest(true, request);
    },

    /**
     * @param {Boolean} isNoData
     * @param {object.} req
     */
    _sendSocketRequest: function (isNoData, req) {
        cc.assert(this._socket);

        if (this.isSocketOpened()){
            //通过json的方法生成请求字符串
            var msg = null;
            if(isNoData){
                msg = JSON.stringify({seq:req.seq, act:req.act});
            }else{
                msg = JSON.stringify({seq:req.seq, act:req.act, data:req});
            }
            cc.log("WebSocketDelegate::send->" + msg);
            this._socket.send(msg);
        } else{
            // todo
        }
    }
});

module.exports = GameNetwork;

  GameProtocols.js

/**
 * Created by skyxu on 2018/10/9.
 */

"use strict";

/**
 * 消息基类对象,请求消息BaseRequest, 回调消息BaseResponse都继承BaseProtocol
 */
let BaseProtocol = cc.Class({
    ctor: function () {
        /**
         * 请求动作类型
         */
        this.act = '';

        /**
         * 每个请求的sequence_id应该唯一
         */
        this.seq = 0;

        /**
         * 错误代码,0为正常
         */
        this.err = 0;

        /**
         * 是否需要等待服务器回调
         */
        this.is_async = false;
    }
});

/**
 * 请求消息基类,客户端的请求都继承这个类
 */
let BaseRequest = cc.Class({
    extends: BaseProtocol
});

/**
 * 服务器返回的消息对应的对象,包含返回数据,一般和BaseRequest成对使用
 * @class BaseResponse
 * @extends BaseProtocol
 */
let BaseResponse = cc.Class({
    extends: BaseProtocol,

    /**
     * 读取返回数据,设置BaseResponse对象
     */
    loadData: function (data) {
        var key;
        for (key in data) {
            if(!this.hasOwnProperty(key)){
                continue;
            }

            if(data[key] !== undefined && data[key] !== null){
                this[key] = data[key];
            }
        }
    }
});

let HeartRequest = cc.Class({
    extends: BaseRequest,
    ctor(){
        this.act = 'heart';
        this.t = -1;    // 发送时间
    }
});

let HeartResponse = cc.Class({
    extends: BaseResponse,

    ctor(){
        this.act = 'heart';
        this.t = -1;
    }
});

let ChatRequest = cc.Class({
    extends: BaseRequest,
    ctor(){
        this.act = 'chat';
        this.msg = '';
        this.uid = '';
    }
});

let ChatResponse = cc.Class({
    extends: BaseResponse,
    ctor(){
        this.act = 'chat';
        this.msg = '';
        this.uid = '';
    }
});

let LoginRequest = cc.Class({
    extends: BaseRequest,

    ctor: function () {
        this.act = 'login';

        /**
         * facebook用户的accessToken,或游客的UUID
         */
        this.token = '';

        /**
         * token来源,默认0:游客,1:facebook
         */
        this.origin = 0;

        /**
         * 平台: 必须为以下几种之一:android/ios/winphone/pc
         */
        this.os = '';

        /**
         * 平台系统版本
         */
        this.osVersion = '';

        /**
         * 设备产品型号, 示例 iPhone8,2, SM-G 9280
         */
        this.deviceModel = '';

        /**
         * 渠道ID
         */
        this.channelId = 0;

        /**
         * Ios设备广告标示符
         */
        this.idfa = '';

        /**
         * 安卓设备id
         */
        this.androidId = '';

        /**
         * Google广告平台账号,安装了google play的设备可取到
         */
        this.googleAid = '';

        /**
         * 应用版本号
         */
        this.appVersion = '';

        /**
         * 取package name或者bundle id
         */
        this.packName = '';


        /**
         * 设备语言
         * @type {string}
         */
        this.language = '';

        this.locale = "";

    }
});

let LoginResponse = cc.Class({
    extends: BaseResponse,

    ctor: function () {
        this.act = 'login';

        /**
         * 游客第一次登录时返回的token,需要客户端保存
         */
        this.token = '';

        /**
         * 离体力下次恢复点的剩余时间秒数
         * @type {number}
         */
        this.spStepLeftTime = 0;

        /**
         * 体力恢复周期
         * @type {Number}
         */
        this.spInterval = 0;

        /**
         * 农场每天产出量,产出未解锁时为-1
         * @type {number}
         */
        this.farmDailyOut = -1;

        /**
         * 农场已产出量
         * @type {number}
         */
        this.farmCoins = 0;

        /**
         * 农场产出间隔
         * @type {number}
         */
        this.farmInterval = null;

        /**
         * 用json object表示的一个player对象,字段说明参见player json对象
         */
        this.me = {};

        /**
         * 建筑数据数组
         * @type {Array}
         */
        this.buildings = [];

        /**
         * 农民数据数组
         * @type {Array}
         */
        this.farms = [];

        /**
         * 富豪数据
         */
        this.cashking = {};

        /**
         * 行星配置
         */
        this.planetCOnf= {};

        /**
         * 农民配置
         */
        this.farmCOnfList= [];

        /**
         * 其他配置
         */
        this.settingCOnf= {};

        /**
         * 好友数据
         */
        this.friends = [];

        /**
         * 好友通缉的目标列表
         */
        this.helpWantList = [];

        /**
         * 邮件消息列表
         */
        this.newsList = [];

        /**
         * 复仇列表
         */
        this.revengeList = [];

        /**
         * 商品信息
         * @type {Array}
         */
        this.rechargeCOnfs= [];

        /**
         * 总岛数
         * @type {Number}
         */
        this.planetCOnfListSize= 0;

        /**
         * 他人行星信息对象,仅在转到fire断线重新登录时有效
         * @type {Object}
         */
        this.fireTarget = null;

        /**
         * 他人行星信息对象列表,仅在转到steal断线重新登录时有效
         * @type {Array}
         */
        this.stealTarget = null;
    }
});

let LogoutRequest = cc.Class({
    extends: BaseRequest,

    ctor: function () {
        this.act = 'logout';
    }
});

let LogoutResponse = cc.Class({
    extends: BaseResponse,

    ctor: function () {
        this.act = 'logout';
    }
});

/**
 * 绑定fb账号
 * @extends BaseRequest
 */
let BindFacebookRequest = cc.Class({
    extends: BaseRequest,

    ctor: function () {
        this.act = 'bindFb';

        /**
         * facebook用户的accessToken,或游客的UUID
         */
        this.token = '';
    }
});
/**
 * 绑定fb账号
 * @extends BaseResponse
 */
let BindFacebookResponse = cc.Class({
    extends: BaseResponse,

    ctor: function () {
        this.act = 'bindFb';

        /**
         * fb数据
         */
        this.me = 0;

        /**
         * fb好友
         */
        this.friends = 0;
    }
});

let SpinRequest = cc.Class({
    extends: BaseRequest,

    ctor: function () {
        this.act = 'spin';

        /**
         * 倍数
         * @type {Number}
         */
        this.x = 1;
    }
});

let SpinResponse = cc.Class({
    extends: BaseResponse,

    ctor: function () {
        this.act = 'spin';

        /**
         * 摇中的转盘ID
         */
        this.hit = 0;

        /**
         * 转到护盾,但护盾已满时,存在
         * @type {number}
         */
        this.shieldfull = 0;

        /**
         * 玩家数据对象
         */
        this.me = {};

        /**
         * 他人行星信息对象,仅在转到fire时有效
         * @type {*}
         */
        this.fireTarget = {};

        /**
         * 偷取对象数据
         */
        this.stealTarget = [];

        /**
         * 离体力下次恢复点的剩余时间秒数
         * @type {number}
         */
        this.spStepLeftTime = 0;

        /**
         * 体力恢复周期
         * @type {Number}
         */
        this.spInterval = 0;

        /**
         * 倍数
         * @type {Number}
         */
        this.x = 1;
    }
});

/**
 * 获取排名
 * @extends BaseRequest
 */
let RankRequest = cc.Class({
    extends: BaseRequest,

    ctor: function () {
        this.act = 'rankboard';

        /**
         * 请求动作类型{ 0全部,1本地,2好友 }
         * @type {int}
         */
        this.type = 0;
    }
});
/**
 * 获取排名
 * @extends BaseResponse
 */
let RankResponse = cc.Class({
    extends: BaseResponse,

    ctor: function () {
        this.act = 'rankboard';

        /**
         *  我的排名
         */
        this.myRank = 0;

        /**
         * 排名玩家数据
         */
        this.men = [];
    }
});


//push------------------------------------------------------------------------------

/**
 * 推送消息 被攻击
 * @extends BaseResponse
 */
var PushAttackedRespOnse= cc.Class({
    extends: BaseResponse,

    ctor: function () {
        this.act = 'attacked';

        /**
         * 玩家更新数据
         */
        this.me = null;

        /**
         * 建筑数据
         */
        this.building = null;

        /**
         * 敌人
         */
        this.hatredman = null;

        /**
         * 消息
         */
        this.news = null;
    }
});


/**
 * 推送消息 推送消息好友已赠送体力
 * @extends BaseResponse
 */
var PushSendSpRespOnse= cc.Class({
    extends: BaseResponse,

    ctor: function () {
        this.act = 'sendSpNotify';

        /**
         * 好友对象
         */
        this.friend = null;
    }
});

/**
 * 推送消息 推送消息好友已领取赠送的体力
 * @extends BaseResponse
 */
var PushTakeSpRespOnse= cc.Class({
    extends: BaseResponse,

    ctor: function () {
        this.act = 'takeSpNotify';

        /**
         * 好友对象
         */
        this.friend = null;
    }
});

/**
 * 推送消息 同步好友信息
 * @extends BaseResponse
 */
var PushSyncFriendInfo = cc.Class({
    extends: BaseResponse,

    ctor: function () {
        this.act = 'friendInfoSync';

        /**
         * 好友
         */
        this.friend = null;
    }
});

/**
 * 推送消息 新增好友
 * @extends BaseResponse
 */
var PushAddNewFriend = cc.Class({
    extends: BaseResponse,

    ctor: function () {

        this.act = 'newFriend';

        /**
         * 好友
         */
        this.friend = null;

        /**
         * 消息
         */
        this.news = null;
    }
});

/**
 * debug回调
 * @extends BaseRequest
 */
let DebugChangeMeRequest = cc.Class({
    extends: BaseRequest,

    ctor: function () {

        this.act = "cmdTest";                    //请求动作类型
        this.cmd = "";
        //  "player coins add 100", cmd格式:player field value 或者 player field add value
        //  Building field [add] value where playerId value type value
    }

});
/**
 * debug回调
 * @extends BaseResponse
 */
let DebugChangeMeResponse = cc.Class({
    extends: BaseResponse,

    ctor: function () {
        this.act = "cmdTest";

        /**
         * 玩家数据
         * @type {Object}
         */
        this.me = {};

        /**
         * 体力恢复周期
         * @type {Number}
         */
        this.spInterval = null;

        /**
         * 体力恢复剩余时间
         * @type {Number}
         */
        this.spStepLeftTime = null;

        /**
         * 存钱罐速度
         * @type {Number}
         */
        this.farmDailyOut = null;

        /**
         * 存钱罐可回收金币
         * @type {Number}
         */
        this.farmCoins = null;

        /**
         * 存钱罐回收周期
         * @type {Number}
         */
        this.farmInterval = null;

        /**
         * 岛屿建筑数据
         * @type {Array}
         */
        this.buildings = null;
    }
});

let response_classes = {
    login: LoginResponse,
    logout: LogoutResponse,
    spin: SpinResponse,
    bindFb: BindFacebookResponse,
    rankboard: RankResponse,
    heart: HeartResponse,
    chat: ChatResponse,

    //push
    attacked: PushAttackedResponse,
    sendSpNotify: PushSendSpResponse,
    takeSpNotify: PushTakeSpResponse,
    newFriend: PushAddNewFriend,
    friendInfoSync: PushSyncFriendInfo,

    // debug
    cmdTest: DebugChangeMeResponse,
};

module.exports = {
    LoginRequest: LoginRequest,
    LoginResponse: LoginResponse,
    LogoutRequest: LogoutRequest,
    LogoutResponse: LogoutResponse,
    SpinRequest: SpinRequest,
    SpinResponse: SpinResponse,
    BindFacebookRequest: BindFacebookRequest,
    BindFacebookResponse: BindFacebookResponse,
    RankRequest: RankRequest,
    RankResponse: RankResponse,
    HeartRequest: HeartRequest,
    HeartResponse: HeartResponse,
    ChatRequest: ChatRequest,
    ChatResponse: ChatResponse,

    // debug
    DebugChangeMeRequest: DebugChangeMeRequest,
    DebugChangeMeResponse: DebugChangeMeResponse,

    //push消息
    PushAttackedResponse: PushAttackedResponse,
    PushSendSpResponse: PushSendSpResponse,
    PushTakeSpResponse: PushTakeSpResponse,
    PushAddNewFriend: PushAddNewFriend,
    PushSyncFriendInfo: PushSyncFriendInfo,

    response_classes: response_classes
};

  NetProxy.js

/**
* Created by skyxu on 2018/10/9.
*/

"use strict";

let GameNetwork = require("./GameNetwork");
let GameProtocols = require("./GameProtocols");

let GAME_SERVER_URL = 'ws://127.0.0.1:3000';
// GAME_SERVER_URL = 'wss://echo.websocket.org';

let NetProxy = cc.Class({
ctor: function () {
this.network = null;
this._cachePushCallback = [];
},

init: function () {
this.network = new GameNetwork();
this.network.setDelegate(this);
this.initPushCallback();
},

connect: function () {
this.network.connect(GAME_SERVER_URL);
},

closeConnect: function () {
this.network.closeConnect();
},

isNetworkOpened: function () {
return this.network.isSocketOpened();
},

isNetworkClosed: function () {
return this.network.isSocketClosed();
},

onNetworkOpen: function () {
Global.eventMgr.emit(Global.config.EVENT_NETWORK_OPENED);
},

onNetworkClose: function () {
Global.eventMgr.emit(Global.config.EVENT_NETWORK_CLOSED);
},

/**
* 注册push回调接口
*/
initPushCallback: function () {
let self = this;
let pushCallback = function (resp) {
self.pushCallback(resp);
};

this.network.registerPushResponseCallback('chat', pushCallback);


// let pushCallback = function(response){
// if(Util.DNN(farm.game) && farm.game.loginSuccess){
// this.dealCachePush();
// this.pushCallback(response);
// }else{
// this._cachePushCallback.push(response);
// }
// }.bind(this);

// this.network.registerPushResponseCallback('attacked', pushCallback);
// this.network.registerPushResponseCallback('acceptWantHelp', pushCallback);
// this.network.registerPushResponseCallback('sendSpNotify', pushCallback);
// this.network.registerPushResponseCallback('takeSpNotify', pushCallback);
// this.network.registerPushResponseCallback('wanted', pushCallback);
// this.network.registerPushResponseCallback('incomplete', pushCallback);
// this.network.registerPushResponseCallback('newFriend', pushCallback);
// this.network.registerPushResponseCallback('news', pushCallback);
// this.network.registerPushResponseCallback('hatredInfoSync', pushCallback);
// this.network.registerPushResponseCallback('friendInfoSync', pushCallback);
},

/**
* 处理缓存push
*/
dealCachePush: function () {
// if(this._cachePushCallback.length > 0){
// for(var i = 0; i // this.pushCallback(this._cachePushCallback[i]);
// }
// }
// this._cachePushCallback = [];
},

beatHeart: function (callback) {
let req = new GameProtocols.HeartRequest();
req.t = Date.now();
this.network.sendRequest(req, callback);
},

chat: function (msg) {
let req = new GameProtocols.ChatRequest();
let uid = cc.sys.localStorage.getItem("chat_uid");
req.uid = uid;
req.msg = msg;
this.network.sendRequest(req);
},

/**
* Facebook或者游客登录接口
* @param {Object.} origin
* @param token
*/
login: function (origin, token) {
// let req = new GameProtocols.LoginRequest();
// if(token) req.token = token;
// req.origin = origin;
// req.os = cc.sys.os;
// req.osVersion = cc.sys.osVersion;
// // req.language = cc.sys.language;//farm.FarmPlatformHelper.jsToOc(farm.FarmPlatformHelper.JSB_EVENT_JTO_GetCurrentLanguage);
// /*
// req.deviceModel = '';
// req.channelId = 0;
// req.idfa = '';
// req.androidId = '';
// req.googleAid = '';
// req.appVersion = '';
// req.packName = '';
// */
// let callback = function (resp) {
// if(resp.err != 0){
// Global.eventMgr.emit(farm.game.gmConst.SP_EVENT_LOGIN_FAILED, resp);
// return;
// }
// if(resp.token && resp.token.length > 0){
// farm.localStorage.setItem(farm.game.gmConst.GLS_KEY_GUEST_TOKEN, resp.token);
// }
// farm.localStorage.removeItem(farm.game.gmConst.GLS_KEY_IS_LOGOUT);
//
// //
// farm.game.initConfig(resp);
// farm.game.initData(resp);
// farm.game.loginSuccess = true;
//
// // js 调取其他平台的sdk,传过去玩家id
// farm.FarmPlatformHelper.jsToOc(farm.FarmPlatformHelper.JSB_EVENT_JTO_setSessionWithUid, farm.game.player.id.toString());
// //
//
// //登录
// farm.eventManager.emit(farm.game.gmConst.SP_EVENT_LOGIN_SUCCESS);
// };
// this.network.sendRequest(req, callback);

},

/**
* Facebook或者游客登出
*/
logout: function () {
// let req = new GameProtocols.LogoutRequest();
// this.network.sendRequest(req, function (resp) {
// if(resp.err != 0){
// cc.log("网络请求---LogoutRequest 失败");
// farm.eventManager.emit(farm.game.gmConst.SP_EVENT_LOGOUT_FAILED);
// return;
// }
// cc.log("网络请求---LogoutRequest 成功");
// Global.eventMgr.emit(farm.game.gmConst.SP_EVENT_LOGOUT_SUCCESS);
// });
},

/**
* 绑定fb账号
* @param {String} token
*/
bindFacebook: function (token) {
// let req = new GameProtocols.BindFacebookRequest();
// req.token = token;
// let callback = function (resp) {
// //绑定过得逻辑
// if(resp.err == farm.game.gmConst.ERROR_USER_HAS_REGISTERED){
// cc.log("网络请求---BindFacebookRequest 已绑定");
// farm.eventManager.emit(farm.game.gmConst.SP_EVENT_HAS_BIND_FACEBOOK);
// return;
// }
// //绑定失败
// if(resp.err != 0){
// cc.log("网络请求---BindFacebookRequest 失败");
// farm.eventManager.emit(farm.game.gmConst.SP_EVENT_BIND_FACEBOOK_FAILED);
// return;
// }
// //绑定成功
// cc.log("网络请求---BindFacebookRequest 成功");
// if(resp.me){
// farm.game.player.parse(resp.me);
// }
// if(resp.friends){
// farm.game.initFriends(resp.friends);
// }
// //绑定成功后删除本地token
// farm.localStorage.removeItem(farm.game.gmConst.GLS_KEY_GUEST_TOKEN);
// farm.eventManager.emit(farm.game.gmConst.SP_EVENT_BIND_FACEBOOK_SUCCESS);
// };
// this.network.sendRequest(req, callback);
},

/**
* 启动转盘
*/
spin: function (x) {
// let req = new GameProtocols.SpinRequest();
// if(farm.util.isNumber(x)){
// req.x = x;
// }
// var callback = function (resp) {
// if(resp.err != 0){
// cc.log("网络请求---spin 失败");
// farm.eventManager.emit(farm.game.gmConst.SP_EVENT_SPIN_FAILED, resp);
// return;
// }
// cc.log("网络请求---spin 成功");
// farm.game.player.parse(resp.me);
// farm.game.spTimer.updateSpTime(resp.spStepLeftTime, resp.spInterval);
// farm.eventManager.emit(farm.game.gmConst.SP_EVENT_SPIN_SUCCESS, resp);
// };
// this.network.sendRequest(req, callback);
},

/**
* 获取排名
* @param {Number} rankType 0全部,1本地,2好友
*/
getRank: function (rankType) {
// let req = new GameProtocols.RankRequest();
// req.type = rankType;
// let callback = function (resp) {
// if(resp.err != 0){
// cc.log("网络请求---getRank 失败");
// Global.eventMgr.emit(farm.game.gmConst.SP_EVENT_GET_RANK_FAILED, resp);
// return;
// }
// cc.log("网络请求---getRank 成功");
// // todo 暂定排名类型
// resp._rankType = rankType;
// //farm.game.initLeaderBoardArray(rankType, resp.myRank, resp.men);
// if(rankType == 2 && resp.men){
// farm.game.updateFriends(resp.men);
// resp.men = farm.game.sortFriendsByStar();
// }
// Global.eventMgr.emit(farm.game.gmConst.SP_EVENT_GET_RANK_SUCCESS, resp);
// };
// this.network.sendRequest(req, callback);
},


//push回调------------------------------------------------------------------------------

/**
* 推送回调
*/
pushCallback: function (response) {
switch (response.act){
case "sendSpNotify":
case "takeSpNotify":
case "friendInfoSync":
this.pushFriendSendTakeSp(response);
break;
case "stole":
this.pushStole(response);
break;
case "attacked":
this.pushAttacked(response);
break;
case "newFriend":
this.pushAddNewFriend(response);
break;
case "chat":
this.pushChat(response);
break;
}
},
/**
* 好友间互赠体力推送
* @param {PushSendSpResponse|PushTakeSpResponse} resp
*/
pushFriendSendTakeSp: function (resp) {
// cc.log("网络请求---push--- pushFriendSendTakeSp 成功");
// if(resp.friend) farm.game.updateFriends(resp.friend);
// farm.eventManager.emit(farm.game.gmConst.SP_PUSH_EVENT_UPDATE_FRIEND);
},

/**
* 被偷
* @param {PushStolenResponse} resp
*/
pushStole: function (resp) {
// cc.log("网络请求---push--- pushStole 成功");
// if(resp.me) farm.game.player.parse(resp.me);
// //if(resp.building) farm.game.buildings[resp.building.type].parse(resp.building);
// if(resp.hatredman && !farm.game.getHelpWant(resp.hatredman.id)){
// farm.game.addEnemy(resp.hatredman);
// }
// if(resp.news){
// resp.news = farm.game.addNews(resp.news);
// }
// farm.eventManager.emit(farm.game.gmConst.SP_PUSH_EVENT_BE_STOLE_SUCCESS, resp);
},

/**
* 被攻击
* @param {PushAttackedResponse} resp
*/
pushAttacked: function (resp) {
// cc.log("网络请求---push--- pushAttacked 成功");
// if(resp.me) {
// farm.game.player.parse(resp.me);
// farm.game.dataUpdater.updateStar();
// }
// if(resp.building) farm.game.buildings[resp.building.type].parse(resp.building);
// if(resp.hatredman){
// farm.game.addBadass(resp.hatredman);
// if(!farm.game.getHelpWant(resp.hatredman.id)){
// farm.game.addEnemy(resp.hatredman);
// }
// }
// if(resp.news){
// resp.news = farm.game.addNews(resp.news);
// }
// farm.eventManager.emit(farm.game.gmConst.SP_PUSH_EVENT_BE_ATTACK_SUCCESS, resp);
},

/**
* 新增好友
* @param {PushAddNewFriend} resp
*/
pushAddNewFriend: function (resp) {
// cc.log("网络请求---push--- pushAddNewFriend 成功");
// if(resp.friend){
// resp.friend = farm.game.addFriend(resp.friend);
// }
// if(resp.news){
// resp.news = farm.game.addNews(resp.news);
// }
// farm.eventManager.emit(farm.game.gmConst.SP_PUSH_EVENT_ADD_FRIEND_SUCCESS, resp);
},

pushChat: function (resp) {
Global.eventMgr.emit(Global.config.EVENT_CHAT, resp);
},

/**
* debug调试请求
* @param {String} name
*/
debug_addCoins: function (name) {
var req = new GameProtocols.DebugChangeMeRequest();
if (name === "btnAddCoins") {
req.cmd = "player coins add 100000000";
} else if (name === "btnClearCoins") {
req.cmd = "player coins 0";
} else if (name === "btnAddEnergy") {
req.cmd = "player sp add 10";
} else if (name === "btnClearEnergy") {
req.cmd = "player sp 0";
} else if (name == "btnAddWp") {
req.cmd = "player wp add 10";
} else if (name == "btnClearWp") {
req.cmd = "player wp 0";
} else if (name == "btnUnwrap"){
req.cmd = "player fbuid null";
} else if (name == "btnWizard1"){
req.cmd = "player wizard1 0";
} else if (name == "btnWizard2"){
req.cmd = "player wizard2 0";
} else if (name == "btnClearShield"){
req.cmd = "player shield 0";
} else if (name == "btnSpEc"){
req.cmd = "SpEc stepInterval 60000";
} else if (name == "btnFarmEc"){
req.cmd = "FarmEc stepInterval 60000";
} else if (name == "btnSpEcBack"){
req.cmd = "SpEc stepInterval 3600000";
} else if (name == "btnFarmBack"){
req.cmd = "FarmEc stepInterval 86400000";
} else if (name == "btnUpdateBuild"){
req.cmd = "Building lv 5";
} else {
req.cmd = name;
}
// var callback = function (resp) {
// if (resp.err != 0) {
// return;
// }
// farm.game.player.parse(resp.me);
// farm.game.spTimer.updateSpTime(resp.spStepLeftTime, resp.spInterval);
// farm.game.dataUpdater.updateCoin();
// farm.game.dataUpdater.updateSp();
// farm.game.dataUpdater.updateShield();
// farm.game.dataUpdater.updateStar();
// //
// if((req.cmd == "FarmEc stepInterval 60000" || req.cmd == "FarmEc stepInterval 86400000")
// && farm.util.isNumber(resp.farmDailyOut)
// && farm.util.isNumber(resp.farmCoins)){
// farm.game.piggyBankTimer.init(resp.farmDailyOut, resp.farmCoins, resp.farmInterval);
// }
// if(req.cmd == "SpEc stepInterval 60000" || req.cmd == "SpEc stepInterval 3600000"){
// farm.game.spTimer.updateSpTime(resp.spStepLeftTime, resp.spInterval);
// }
// if(resp.buildings){
// for(var i = 0; i // farm.game.buildings[i].parse(resp.buildings[i]);
// }
// farm.eventManager.emit(farm.game.gmConst.SP_EVENT_UPGRADE_BUILDING_SUCCESS, resp);
// farm.eventManager.emit(farm.game.gmConst.SP_DEBUG_EVENT_BUILD_TO_24_SUCCESS, resp);
// }
// };
// this.network.sendRequest(req, callback);
},
});

module.exports = NetProxy;

2、服务端

 使用express + express-ws组件,调用WSRouter的init初始化连接即可,

let expressWS = require('express-ws');
let work = require('./work');

let wsRouter = null;

function WSRouter(app, server){
    this.app = app;
    this.server = server;
    this.clients = [];
    expressWS(app, server);

    this.listenClientCOnnection= ()=>{
        app.ws('/', (socket, req)=>{
            console.log('client connect to server successful.');
            this.clients.push(socket);
            console.log('clients: ' + this.clients.length);
            socket.on('message', (msg)=>{
                console.log('on message: ' + msg);
                work(this, socket, msg);
            });

            socket.on('close', (msg)=>{
                console.log('on close: ' + msg);
                for (let index=0; index<this.clients.length; index++){
                    if (this.clients[index] == socket){
                        this.clients.splice(index,1);
                    }
                }
                console.log('clients: ' + this.clients.length);
            });

            socket.on('error', (err)=>{
                console.log('on error: ' + error);
            });
        })
    }
}


module.exports = {
    init: function(app, server){
        if (wsRouter == null){
            wsRouter = new WSRouter(app, server);
        }
        return wsRouter;
    }
}
module.exports = function(wsRouter, ws, msg){
    let msgObj = JSON.parse(msg);
    switch (msgObj.act){
        case 'heart':{
            msgObj.data.t = Date.now();
            ws.send(JSON.stringify(msgObj));
            break;
        }
        case 'chat': {
            for (let w of wsRouter.clients){
                w.send(msg);
            }
            break;
        }

        default:
            break;
    }
}

 


推荐阅读
  • OpenMap教程4 – 图层概述
    本文介绍了OpenMap教程4中关于地图图层的内容,包括将ShapeLayer添加到MapBean中的方法,OpenMap支持的图层类型以及使用BufferedLayer创建图像的MapBean。此外,还介绍了Layer背景标志的作用和OMGraphicHandlerLayer的基础层类。 ... [详细]
  • 基于PgpoolII的PostgreSQL集群安装与配置教程
    本文介绍了基于PgpoolII的PostgreSQL集群的安装与配置教程。Pgpool-II是一个位于PostgreSQL服务器和PostgreSQL数据库客户端之间的中间件,提供了连接池、复制、负载均衡、缓存、看门狗、限制链接等功能,可以用于搭建高可用的PostgreSQL集群。文章详细介绍了通过yum安装Pgpool-II的步骤,并提供了相关的官方参考地址。 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 本文讨论了在Windows 8上安装gvim中插件时出现的错误加载问题。作者将EasyMotion插件放在了正确的位置,但加载时却出现了错误。作者提供了下载链接和之前放置插件的位置,并列出了出现的错误信息。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • 本文介绍了九度OnlineJudge中的1002题目“Grading”的解决方法。该题目要求设计一个公平的评分过程,将每个考题分配给3个独立的专家,如果他们的评分不一致,则需要请一位裁判做出最终决定。文章详细描述了评分规则,并给出了解决该问题的程序。 ... [详细]
  • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
    转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
  • 不同优化算法的比较分析及实验验证
    本文介绍了神经网络优化中常用的优化方法,包括学习率调整和梯度估计修正,并通过实验验证了不同优化算法的效果。实验结果表明,Adam算法在综合考虑学习率调整和梯度估计修正方面表现较好。该研究对于优化神经网络的训练过程具有指导意义。 ... [详细]
  • WebSocket与Socket.io的理解
    WebSocketprotocol是HTML5一种新的协议。它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送 ... [详细]
  • 本文介绍了机器学习手册中关于日期和时区操作的重要性以及其在实际应用中的作用。文章以一个故事为背景,描述了学童们面对老先生的教导时的反应,以及上官如在这个过程中的表现。同时,文章也提到了顾慎为对上官如的恨意以及他们之间的矛盾源于早年的结局。最后,文章强调了日期和时区操作在机器学习中的重要性,并指出了其在实际应用中的作用和意义。 ... [详细]
  • 本文介绍了使用Spark实现低配版高斯朴素贝叶斯模型的原因和原理。随着数据量的增大,单机上运行高斯朴素贝叶斯模型会变得很慢,因此考虑使用Spark来加速运行。然而,Spark的MLlib并没有实现高斯朴素贝叶斯模型,因此需要自己动手实现。文章还介绍了朴素贝叶斯的原理和公式,并对具有多个特征和类别的模型进行了讨论。最后,作者总结了实现低配版高斯朴素贝叶斯模型的步骤。 ... [详细]
  • [echarts] 同指标对比柱状图相关的知识介绍及应用示例
    本文由编程笔记小编为大家整理,主要介绍了echarts同指标对比柱状图相关的知识,包括对比课程通过率最高的8个课程和最低的8个课程以及全校的平均通过率。文章提供了一个应用示例,展示了如何使用echarts制作同指标对比柱状图,并对代码进行了详细解释和说明。该示例可以帮助读者更好地理解和应用echarts。 ... [详细]
author-avatar
手浪用户2602928711
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有