webSocket原理及客户端实战:接收实时消息

需求:

需求实现监听服务端推送过来的消息,效果见下图:
用户某一个动作触发消息发送,在监听接口收到消息并展示出来。


11565434-1cf3a1557712c128.gif
接收实时消息.gif

解决方案:

ajax轮询(短轮询)

原理:客户端每隔几秒就发送一次请求,服务器接到请求后马上返回响应信息并关闭连接。
优点:程序编写比较容易。
缺点:请求次数多,请求中有大半是无用,浪费带宽和服务器资源。

long poll (长轮询)

原理:跟ajax轮询差不多,都是采用轮询的方式,区别在于:服务端收到请求后,检测数据是否有新数据,有则立即返回并关闭,无则挂起一直不返回Response直到超时关闭。关闭后客户端再次发起请求建立连接,周而复始。
优点:客户端的请求次数会大量减少
缺点:服务端请求挂起同样会导致资源的浪费

小结:
1.HTTP协议是基于请求/响应模式的,因此只要服务端给了响应,本次HTTP连接就结束了。
2.Ajax轮询与long poll都属于不断发送http请求,然后等待服务器处理,可以看到http协议一个特点,被动性

webSocket

webSocket是html5一种新的协议,实现了浏览器与服务器之间的全双工通信,能很好的节省服务器资源与带宽,并在服务器端与浏览器端实现实时通行,他建立在TCP之上, 同http一样,通过tcp来传输数据。

WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

11565434-613fed6580369284.png
image.png
11565434-0efd259734ffb289.png
image.png

webSocket客户端实例

使用如下的代码可以实现上面图片收到实时消息的效果。

//实时消息
  startWebSocket(){
        let this_=this;
        let wsUrl=urlConfig.wsUrl+localStorage.getItem("access_token");//websocket接口地址
        let ws = new WebSocket(wsUrl);
        ws.onclose = function () {
            this_.reConnect(wsUrl);//重新连接
            console.log("连接已关闭 "+new Date());
        };
        ws.onerror = function () {
            this_.reConnect(wsUrl);//重新连接
            console.log("连接异常 "+new Date());
        };
        ws.onopen = function () {
            heartCheck.reset().start();//开始心跳检测
            console.log("连接成功 "+new Date());
        };
        ws.onmessage = function (e) {
            heartCheck.reset().start();//开始心跳检测
            let data = JSON.parse(e.data);
            this_.onMessageNotice(data);//获取到数据的回调
        };

        /*心跳检测:
            1.如果当前连接着(onopen或onMessage),就开始心跳检测,即设置定时器一段时间后发送一条数据,发送后再过一段时间关闭连接;
              如果在关闭之前,后端正常返回数据(会触发onMessage),会重置心跳检测就一直不会关闭连接。
            2.如果当前异常或关闭(onclose,onerror),就重新建立连接;
        */
        let heartCheck = {
            timeout: 180000,        //3分钟发一次心跳
            timeoutObj: null,//定时器:延时发送一次心跳
            serverTimeoutObj: null,//定时器:延时检测后端是否返回数据,如返回则还连着,如未返回则后端断了
            reset: function(){
                clearTimeout(this.timeoutObj);
                clearTimeout(this.serverTimeoutObj);
                return this;
            },
            start: function(){
                let this_ = this;
                this.timeoutObj = setTimeout(function(){
                    ws.send("peng");
                    console.log("peng");
                    this_.serverTimeoutObj = setTimeout(function(){//如果超过一定时间还没重置,说明后端主动断开了
                        ws.close();     //如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
                    }, this_.timeout)
                }, this.timeout)
            }
        };
  }

//重新连接websocket
    reConnect(url) {
        let this_=this;
        if(this.lockReconnect) return;
        this.setState({
            lockReconnect:true//上锁
        });
        setTimeout(function () {     //没连接上会一直重连,设置延迟避免请求过多
            this_.startWebSocket(url);
            this_.setState({
                lockReconnect:false//开锁
            });
        }, 5000);
    }
//收到消息的回调
    onMessageNotice(data){
        notification.info({//antd 中的组件
            message: "这是一条消息",
            description: "消息描述",
        });
        //收到消息重新获取消息列表
        this.getNewsList();
        //播放声音
        this.refs.audio.play();
    }

猜你喜欢

转载自blog.csdn.net/weixin_33860722/article/details/87024531