使⽤cocoscreator+node.js+websocket实现简单的聊天服务先上个效果图:
使⽤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 () {
},
initMsg(msg, uid){
this.msgLabel.string = msg;
this.uidLabel.string = uid;
this.msgLabel.overflow = cc.Label.Overflow.NONE;
/
/ this.msgBg.width = de.width + 10;
// this.msgBg.height = de.height + 10;
// de.height = this.msgBg.height + 40;
this.scheduleOnce((dt)=>{
if ( de.width >= this.maxLen){
this.msgLabel.overflow = cc.Label.Overflow.RESIZE_HEIGHT;
de.width = this.maxLen;
}
this.msgBg.width = de.width + 10;
this.msgBg.height = de.height + 10;
}, 0);
}
// update (dt) {},
});
⽹络部分分成了四层:
1、socket 封装基础的websocket, 这⾥是最底层,也是真正链接的开始
2、network 控制socket链接层,实现各回调接⼝
3、netproxy 封装各服务功能,把长连接变成短连接的请求⽅式
4、netprotocols 和服务器协商,确定每个请求的请求体格式和回复格式
各部分代码如下:
GameWebSocket.js:
/**
* @enum {number}
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 服务器地址
前端websocket怎么用* @param {GameWebSocketDelegate} 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);
this._SocketMessage(param.data);
}.bind(this);
// function({code: Number, reason: String, wasClean: Boolean})} ws.onclose = function (param) {
this._ason);
}.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', String());
}
this._webSocket = null;
},
getState: function () {
if (this._webSocket) {
switch(this._adyState){
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;
}
});
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.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.<string, function(object.<string, *>)>}
*/
this.pushResponseCallback = {};
/**
* 根据seq保存Request和其callback,以便在收到服务器的响应后回调
* @type {Object.<int, NetworkCallback>}
* @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._State() == 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._t();
},
closeConnect: function () {
if(this._socket){
this._socket.close();
}
},
onSocketOpen: function () {
cc.log('Socket:onOpen');
if(this._delegate && this._NetworkOpen){
this._NetworkOpen();
}
},
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._NetworkClose){
this._NetworkClose();
}
},
onSocketMessage: function (msg) {
this._onResponse(msg);
},
_onResponse: function(responseData){
cc.log('response->resp:', responseData);
var responseJson = JSON.parse(responseData);
var responseClass = sponse_classes[responseJson.act];
/**
* @type {object.<BaseResponse>}
*/
var response = new responseClass();
response.loadData(responseJson.data);
response.act = responseJson.act;
response.seq = responseJson.seq;
< = ;
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];
// }
}
}
//有错,且不忽略,则统⼀处理错误
&& != response_state.ERROR_OK && !ignoreError){ if (response.is_async) { // 异步请求,如果出错了,应该需要重新登录
// todo 重新登录?或者重新同步数据?
} else { // 同步请求,如果出错了,需要显⽰错误信息
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论