cocoscreator与nodejs网络基础通信(一)

WebSocket是一种在TCP连接上进行全双工通信的协议。做h5游戏的时候经常会用到。

概念就不进行讲解了。主要教大家怎么使用。内容比较基础,高手可以忽略。

其中为了讲得通俗易懂,描述得不一定完全准确,请大家谅解。

游戏客户端使用cocoscreator,服务器使用nodejs。通信主要使用websocket,消息协议使用的protobuf。

这里先教大家怎么使用的websocket和nodejs进行通信,后面再教大家使用protobuf将二者整合。

首先讲解cocoscreator使用websocket:

var websocket = new WebSocket(url);//创建一个websocket

websocket的数据传输有两种格式,一种是字符串,一种是二进制。

因为我们这里需要和protobuf进行整合,所以主要讲解以二进制方式传输数据。

websocket.binaryType = "arraybuffer";//设置binaryType,如果是字符串,则设置为"text"。

然后监听websocket事件,即设置时间回调函数。有onopen,onmessage,onerror,onclose。

onopen:在和服务器端建立连接后触发。

onmessage:在收到服务器端数据后触发。传统tcp长连接传输数据需要解决粘包问题,websocket不需要。

onclose:在和服务器端断开连接后触发。

onerror:出现某些错误会触发,比如服务器连接不上,传输数据错误等。

部分代码片段如下:

    self._socket = new WebSocket(self.url);
    self._socket.binaryType = "arraybuffer";
    self._socket.onopen = self.onopen.bind(this);
    self._socket.onmessage = self.onmessage.bind(this);
    self._socket.onerror = self.onerror.bind(this);
    self._socket.onclose = self.onclose.bind(this);

当调用new WebSocket()时,会向服务器发起一个连接请求,如果连接成功,则会回调onopen函数,

如果对端不可到达或者出现某些其它错误,则会回调onerror函数。

部分代码片段如下:

InternalSocket.prototype.onopen = function (event) {
    cc.log("client connection establish.");
    var self = this;
    self.clearHBTimer(); //重置心跳定时器
    self.clearReconnetTimer(); //重置断线重连定时器
    self.heartBeat(); //开始心跳
    if (this._first) {
        this._first = 0; //如果是首次连接,则回调上层连接消息
        self._handle(cc.SYS_MSG.CONNECT, {});
    }
    else {
        //如果不是首次连接,则回调上层重连消息
        self._handle(cc.SYS_MSG.RECONNECT, {});
    }
    this._retryTimes = 0;//重置重连次数
};

InternalSocket.prototype.onmessage = function (event) {
    //cc.log("recv data " + event.type);
    var self = this;
    var orig_buf = event.data;
    if (cc.sys.isNative) {
        self.onmessageNative(orig_buf);//处理app端
    } 
    else {
        self.onmessageOther(orig_buf);//处理h5
    }
};

InternalSocket.prototype.onerror = function (event) {
    var self = this;
    cc.log("websocket error . State : " + self.readyState());
    cc.log(JSON.stringify(event));
    //if (event.type == "error") {};
    self.clearHBTimer();//清除心跳
    if (!!self._socket)
        self._handle(cc.SYS_MSG.ERROR, { readyState: self._socket.readyState });
};

下面讲解前端一些细节:

首先是断线重连,当客户端和服务器断开连接过后,客户端可以每隔一段时间去向服务器发起重连请求。当重试过一定次数过后还不成功,将不再发起重连。目前代码中是无限次数重连。

部分代码片段如下:

InternalSocket.prototype.onclose = function (event) {
    var self = this;
    cc.log("websocket close . State : " + self.readyState());
    self.clearHBTimer(); //清除心跳
    self._handle(cc.SYS_MSG.CLOSE, {}); //触发一次close
    self._socket = null; //置空

    //当没超过重连次数,定时重连
    if (self._retryTimes < cc.MAX_RECONNECT_TIMES) {
        //self._retryTimes++;
        if (self._reconnetTimer === null) {
            self._reconnetTimer = setInterval(function () {
                if (self._retry == 0) return;//判断是否开启了重连功能
                self.connect();//向服务器发起连接
            }, cc.RECONNECT_TIME);
        }
    }
};

然后是收到服务器的消息进行解析

传统的TCP消息因为要处理粘包,所以数据形式一般为 消息号+消息长度+消息内容,websocket则一般为 消息号+消息内容

简单的情况下消息号和消息长度是固定2字节或者4字节长度,稍微复杂一点消息长度可设计成为变长。

这里我们消息长度固定为一个2字节的整型,能够满足基本需求。

需要注意的是,cocoscreator的app端和h5处理消息过程有一定差别。

app端部分代码片段如下,可暂时忽略掉protobuf解析部分,后面会讲到:

InternalSocket.prototype.onmessageNative = function (buf) {
    var self = this;
    var orig_len = buf.byteLength;//获取字节长度
    var dv = new DataView(buf);//使用DataView视图从ArrayBuffer对象中读取数据
    var msgid = dv.getInt16(0, false); //将前两个字节读取为消息号,false表示大端字节序
    if ((orig_len - 2) >= 0) {//剩下的字节数要大于等于0
        var dist_buf = new ArrayBuffer(orig_len - 2);//新建一段内存
        var msg_buf = new Uint8Array(dist_buf);
        var offset = 2;
        //下面把剩下的消息体取到msg_buf中
        for (var i = 0; i < orig_len - 2; i++) {        
            msg_buf[i] = dv.getUint8(offset, false);
            offset++;
        }
        //找到具体对应的protobuf解析
        var msg_root = cc.protoRoot[msgid];
        if (msg_root) {
            cc.log("recv msgid ---> " + msgid + " : " + msg_root.name);
            var msg = msg_root.decode(msg_buf);
            //得到一个json消息数据。
            try {
                //消息逻辑处理
                self._handle(msgid, msg);
            }
            catch (err) {
                throw err;
            }
        }
        else {
            cc.log("decode msg fail.");
        }
    }
    else {
        cc.log("msg length error");
    }
};

总结一下,一个简单的websocket客户端网络部分,除了正常的连接、消息处理,还应该包含心跳机制、断线重连、错误情况处理等。这里给大家讲解了基础的用法。其中的代码变量或某些细节不用太过纠结,后面整个讲解完成后,会把代码全部提供给大家参考。上述消息处理的h5相关代码不在这里贴出了,提供的代码中会有。

下一章将会介绍nodejs使用websocket。

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值