jq封装websocket插件,实现聊天室重连机制、心跳机制

此jq封装方法来自于这里

代码简单易懂,如下:
//jqwebsocket.js
//==========websocket
(function($) {
    $.websocket = function(options) {
        var defaults = {
            domain: top.location.hostname,
            port:3398,
            protocol:""
        };
        var opts = $.extend(defaults,options);
        var szServer = "ws://" + opts.domain + ":" + opts.port + "/" + opts.protocol;
        var socket = null;
        var bOpen = false;
        var t1 = 0; 
        var t2 = 0; 
        var messageevent = {
            onInit:function(){
                if(!("WebSocket" in window) && !("MozWebSocket" in window)){  
                    return false;
                }
                if(("MozWebSocket" in window)){
                    socket = new MozWebSocket(szServer);  
                }else{
                    socket = new WebSocket(szServer);
                }
                if(opts.onInit){
                    opts.onInit();
                }
            },
            onOpen:function(event){
                bOpen = true;
                if(opts.onOpen){
                    opts.onOpen(event);
                }
            },
            onSend:function(msg){
                t1 = new Date().getTime(); 
                if(opts.onSend){
                    opts.onSend(msg);
                }
                socket.send(msg);
            },
            onMessage:function(msg){
                t2 = new Date().getTime(); 
                if(opts.onMessage){
                    opts.onMessage(msg.data,t2 - t1);
                }
            },
            onError:function(event){
                if(opts.onError){
                    opts.onError(event);
                }
            },
            onClose:function(event){
                if(opts.onclose){
                    opts.onclose(event);
                }
                if(socket.close() != null){
                    socket = null;
                }
            }
        }

        messageevent.onInit();
        socket.onopen = messageevent.onOpen;
        socket.onmessage = messageevent.onMessage;
        socket.onerror = messageevent.onError;
        socket.onclose = messageevent.onClose;
        
        this.send = function(pData){
            if(bOpen == false){
                return false;
            }
            messageevent.onSend(pData);
            return true;
        }
        this.close = function(){
            messageevent.onClose();
        }
        return this;
    };
})(jQuery);

封装成jQuery主要是为了使代码更加的简洁,易懂,十分合适新手阅读,使用方法如下:(使用时必须引入上面的代码,jqwebsocket.js)

//=========启动一个websocket
    var Socket1 = $.websocket({
        domain:"www.qhnovel.com",   //这是与服务器的域名或IP
        port:8080,                  //这是服务器端口号
        protocol:"text",            //这东西可有可无,组合起来就是 ws://www.qhnovel.com:8080/test
        //这个是连接后台服务器成功后,回调的函数
        onOpen:function(event){
            console.log("已经与服务端握手,onOpen可省略不写");
        },
        //这个是连接后台服务器失败后,回调的函数
        onError:function(event){
            console.log("发生了错误,onError可省略不写");
        },
        //这个是Socket1.send()发送成功后,回调的函数
        onSend:function(msg){
            console.log("发送数据额外的代码,可省略不写");
        },
        //这个是收到后台放回的数据后的回调函数
        onMessage:function(result,nTime){
            console.log("从服务端收到的数据:" + result);
            console.log("最近一次发送数据到现在接收一共使用时间:" + nTime);
        }
    });
    //=========发送数据方式
    Socket1.send("要发送的数据");
    //=========关闭连接
    Socket1.close();

到这来,聊天室前端的websocket的基本骨架完成了。能够通过WebSocket来发送字符串了,如果需要发送文件、图片其他的,可以在onSend中使用http等其他协议跨平台请求。
对于WebSocket 来说,它必须依赖 HTTP 协议进行一次握手 ,握手成功后,数据就直接从 TCP 通道传输。而平常的post表单提交都是http协议的,说这个是为心跳机制做铺垫,基于tcp连接消耗小,而http的话,消耗较大,所以我们一般使用tcp来发送心跳,就是ws.send(‘ping’);

聊天室重连机制、心跳机制代码如下:

1、对插件的一些小修改,我是为了web移动端的浏览器切换后台或熄屏后,有重新切换到聊天室的重连处理

//==========websocket
(function($) {
    $.websocket = function(options) {
        var defaults = {
            domain: top.location.hostname,
            port:3398,
            protocol:""
        };
        var opts = $.extend(defaults,options);
        var szServer = "ws://" + opts.domain + ":" + opts.port + "/" + opts.protocol;
        var socket = null;
        var bOpen = false;
        var t1 = 0; 
        var t2 = 0; 
        var messageevent = {
            onInit:function(){
                if(!("WebSocket" in window) && !("MozWebSocket" in window)){  
                    return false;
                }
                if(("MozWebSocket" in window)){
                    socket = new MozWebSocket(szServer);  
                }else{
                    socket = new WebSocket(szServer);
                }
                if(opts.onInit){
                    opts.onInit();
                }
            },
            onOpen:function(event){
                bOpen = true;
                if(opts.onOpen){
                    opts.onOpen(event);
                }
            },
            onSend:function(msg){
                t1 = new Date().getTime(); 
                if(opts.onSend){
                    opts.onSend(msg);
                }
                socket.send(msg);
            },
            onMessage:function(msg){
                t2 = new Date().getTime(); 
                if(opts.onMessage){
                    opts.onMessage(msg.data,t2 - t1);
                }
            },
            onError:function(event){
                if(opts.onError){
                    opts.onError(event);
                }
            },
            onClose:function(event){
                if(opts.onclose){
                    opts.onclose(event);
                }
                if(socket.close() != null){
                    socket = null;
                }
                //websocket关闭的时候,判断是否浏览器的情况
                if(document.visibilityState=='hidden') {
                    //页面被隐藏或调到后台的情况,我们这就不做处理
                }else{
                //页面还在时异常被关闭才进行重连
                    console.log("Close回调函数,自动重连")
                    reconnect();
                }
                
            }
        }

        messageevent.onInit();
        socket.onopen = messageevent.onOpen;
        socket.onmessage = messageevent.onMessage;
        socket.onerror = messageevent.onError;
        socket.onclose = messageevent.onClose;
        
        this.send = function(pData){
            if(bOpen == false){
                return false;
            }
            messageevent.onSend(pData);
            return true;
        }
        this.close = function(){
            messageevent.onClose();
        }
        return this;
    };
})(jQuery);

2、重连+心跳 机制

//=========启动一个websocket
 var Socket1;
   Socket1 = $.websocket({
        domain:"www.qhnovel.com",   //这是与服务器的域名或IP
        port:8080,                  //这是服务器端口号
        protocol:"text",            //这东西可有可无,组合起来就是 ws://www.qhnovel.com:8080/test
        onOpen:function(event){
            alert("已经与服务端握手,onOpen可省略不写");
            heartCheck.reset().start(); //传递心跳信息
        },
        onError:function(event){
            alert("发生了错误,onError可省略不写");
            reconnect();//断开重连
        },
        onSend:function(msg){
            alert("发送数据额外的代码,可省略不写");
             if(sen_flag == 2){
	            //已经ping过去了
	            console.log('ping');
	        } else{
	        	//用来处理正常的聊天室消息
			}
        },
        onMessage:function(result,nTime){
        //我这用result == 'pong'有个大大大的前提,就是ping给后台的时候,后台是直接推送pong回来给我的,所以我这里可以直接的判断result == 'pong'
	        if(result == 'pong'){
	            console.log('pong');
	            //如果获取到消息,心跳检测重置 
	            //拿到任何消息都说明当前连接是正常的 
	            heartCheck.reset().start();
	        }
            alert("从服务端收到的数据:" + result);
            alert("最近一次发送数据到现在接收一共使用时间:" + nTime);
        }
    });
//这个是我在具体项目中用来辨别心跳和正常消息的标志位
var sen_flag = 1;
//避免重复连接 
var lockReconnect = false;
// 重连函数
function reconnect(){
    console.log("websocket正在重新连接")
    if (lockReconnect) return; 
    lockReconnect = true; //没连接上会一直重连,设置延迟避免请求过多 
    setTimeout(function() { 
        getwebsocket();
        lockReconnect = false; 
    }, 5000);
}

//心跳检测
 var heartCheck = {
    timeout: 60000, //60秒
    timeoutObj: null,
    serverTimeoutObj: null,
    reset: function() {
        clearTimeout(this.timeoutObj);
        clearTimeout(this.serverTimeoutObj);
        return this;
    },
    start: function() {
        var self = this;
        this.timeoutObj = setTimeout(function() {
            //这里发送一个心跳,后端收到后,返回一个心跳消息,
            //onmessage拿到返回的心跳就说明连接正常
            sen_flag = 2;
            Socket1.send("ping");
            sen_flag = 1;
            self.serverTimeoutObj = setTimeout(function() { //如果超过一定时间还没重置,说明后端主动断开了
                console.log('未收到pong,后端已断开');
                Socket1.close(); 
                //如果onclose会执行reconnect我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
            }, self.timeout)
        }, this.timeout)
    }
}
//当visibilityState流浪器的状态改变时,进行监听
document.addEventListener('visibilitychange',function() {
    if(document.visibilityState=='hidden') {
    //页面被隐藏或调到后台
                    
    }else{
    //页面还在时异常被关闭才进行重连
        console.log("Close回调函数,自动重连")
        reconnect();
    }
})

参考的文章有:https://blog.csdn.net/weixin_42790916/article/details/89640891
https://blog.csdn.net/z_demon801/article/details/85097059
若有更好的写法,欢迎分享。

发布了5 篇原创文章 · 获赞 2 · 访问量 4433

猜你喜欢

转载自blog.csdn.net/Linzsong/article/details/99776603