本方法是自己写的一个JS封装类,用于客户的机于服务器端的通讯,后端我用python完成的代码后期放出来,之前遇到过一个坑爹的问题就是客户端的粘包问题,原因是为了提高数据包效率同时发送的代码被粘在一起发送导致,目前无法解决,在网上找到了很多例子但是都不满足需要,有解决方案就是发送报头,后期如果解决会陆续跟进更新
/**
* WebSocket类 - 包含[ 断线重连, 心跳检测, 粘包抑制 ]
* @param __TF [true自动启动,默认false] 或 {
* host:str ws://地址:端口,
* name:str 客户端名称,
* onopen:fun 握手成功后触发,
* onclose:fun 关闭会话后触发,
* onmessage:fun 接收信息是触发,
* autoLink:bool 是否自动重连
* auto:bool 是否自动启动
* }
* @returns {SKT}
* @constructor {
* onopen:fun 握手成功后触发,
* onclose:fun 关闭会话后触发,
* onmessage:fun 接收信息是触发,
* start:fun 开始握手,
* send:fun(str) 发送信息,
* close|stop:fun 停止方法,
* host:str ws://地址:端口,
* name:str 客户端名称,
* autoLink:bool 是否自动重连,默认true
* }
*/
var WSK=function(__TF){
this.host="ws://127.0.0.1";this.socket=null;this.name='';
this.autoLink=!0; //--允许断线重连
this.onopen = function(s){if(typeof s == 'function')this.onopen=s;};
this.onmessage = function(msg){if(typeof msg == 'function'){this.onmessage=msg;}};
this.onclose = function(s){if(typeof s == 'function'){this.onclose=s;}};
/**
* 开启一个握手会话
*/
this.start=function() {
try {
var that=this;
this.socket = new WebSocket(this.host);
this.socket.onopen = function () {
that.__autoLink_num=0;
clearTimeout(this.__autoLink_t);
that.socket.send('__reg__:' + that.name);
that.__hart();//--定时心跳----
that.onopen();
};
this.socket.onmessage = function (e) {
if(e.data == '__quit__'){
that.close(); return !0;
}
var s = that.onmessage(e.data);
if (s === undefined || s === null) return !0;
that.send(s);
};
this.socket.onclose = function () {
that.__autoLink(); //--握手尝试器
};
}
catch (ex) {
this.__autoLink();
}
};
/**
* 关闭通讯
* @type {WSK.stop}
*/
this.close = this.stop = function () {
clearTimeout(this.__autoLink_t);
this.autoLink=!1; //告诉系统不用重试了本操作是人工或服务端停止的
this.__tmp=[]; //清空排队阵列
try {this.socket.close();}catch (ex) {}
};
/**
* 发送数据到服务端 引入排队机制规避粘包问题
* @param msg 要发送的信息
* @returns {boolean}
*/
this.send = function (msg) {
if (msg === undefined || msg === null) return !1;
var that=this;
try{
if(typeof msg == "boolean") msg=msg?'!0':'!1';//--布尔类型就转换一下形式
else msg=JSON.stringify(msg);
}catch(e){msg=msg.toString();}
this.__tmp.push(msg);
if(that.__t === undefined) {//--阻止粘包事件策略------------
this.__t = setInterval(function () {
if (that.socket.bufferedAmount == 0) //--如果缓冲区在忙碌及等定时器下一轮
if (that.__tmp.length) {
try{
that.socket.send(that.__tmp[0]);
}catch (e) {}that.__tmp.splice(0, 1);
} else {
clearInterval(that.__t);
that.__t = undefined;
}
}, 5);
}
};
this.__tmp=[];//--排队缓存
/**
* 定时器心跳
* @param T
* @returns {boolean}
*/
this.__hart=function(T){
if(socket.readyState==2 || socket.readyState==3) return !1;
if(T) socket.send('__reg__'); //--心跳
setTimeout(function () {
this.__hart(1);//log('心跳')
},5000);
};
/**
* 自动重连内置方法
* @private
*/
this.__autoLink_t={};//--重试定时器
this.__autoLink_num=0;//--重复计数器--
this.__autoLink = function () {
if(this.autoLink){
var that = this;
this.__al_time=this.__al_time?this.__al_time:1000;
this.__autoLink_t=setTimeout(function () {
that.__autoLink_num++;
if(that.__autoLink_num>2){
that.__al_time = 5000;
}
if(that.__autoLink_num>10){
console.log('放弃尝试....');
that.autoLink=!1;
that.onclose();
return !1;
}
console.log('['+that.__autoLink_num+'] 尝试重连...');
that.start();
},this.__al_time);
}else this.onclose();
};
if(typeof __TF == 'object' && __TF){ //--传递参数--赋值
if(__TF.hasOwnProperty('host'))this.host=__TF['host'];
if(__TF.hasOwnProperty('name'))this.name=__TF['name'];
if(__TF.hasOwnProperty('onopen') && typeof __TF['onopen'] == 'function')this.onopen(__TF['onopen']);
if(__TF.hasOwnProperty('onclose') && typeof __TF['onclose'] == 'function')this.onclose(__TF['onclose']);
if(__TF.hasOwnProperty('onmessage') && typeof __TF['onmessage'] == 'function')this.onmessage(__TF['onmessage']);
if(__TF.hasOwnProperty('autoLink'))this.autoLink=__TF['autoLink']?true:false;
if(__TF.hasOwnProperty('auto') && __TF['auto'])this.start();
}else if(__TF === true) this.start();
return this;
};
调用实例:
/**---配置参数目录----------------------*/
window.o=WSK({
host:"ws://服务器地址:端口",
name:'客户端名称'
});
o.onopen(function(){
console.log('成功握手')
});
o.onmessage(function(msg){
console.log(msg)
});
o.onclose(function(){
console.log('连接断开')
});
$("#start").click(function () {
o.start();
});
$("#stop").click(function () {
o.stop();
});
服务器端,命令参考,功能需要您自行编写:
接收来自客户端的命令:
__reg__:注册名称 服务器端先握手再接收注册,指定时间内不注册断开握手(看作登录吧)
__reg__ 心跳检测 服务器端接收心跳,如果心跳不存在就断开客户端连接
评论 (0)