WebSocket 简介 连接的过程 报文 使用 心跳 断开重连

333 阅读3分钟
  1. WebSocket简介?
  • WebSocket是一个网络协议,跟HTTP协议基本没有关系,为了兼容现有浏览器的握手规范,借用了HTTP的协议来完成握手。HTTP协议只能由客户端发送请求,服务器不能主动联系客户端,然而WebSocket可以使客户端和服务器均可主动发送请求。
  • WebSocket对象提供了一组API,用于创建和管理WebSocket连接,以及通过连接接收和发送数据。
  1. WebSocket建立连接的过程?

当Web应用程序调用new WebSocket(url)接口时,Browser就开始了与地址为url的WebServer建立握手连接的过程。

  • Brower与WebSocket服务器通过TCP握手建立连接,如果这个建立连接失败,那么后面的过程就不会执行,Web应用程序将收到错误信息通知。
  • 在TCP建立连接成功后,Browser通过http协议传送WebSocket支持的版本号,原始地址,主机地址等等一系列字段给服务器端。
  • WebSocket服务器收到Browser发送来的请求后,如果数据包数据和格式正确,客户端和服务器端的协议版本号匹配等,就接受本次握手连接,并给出相应的数据回复,同样回复的数据包也是采用http协议传输。
  • Browser收到服务器回复的数据后,如果数据内容等没有问题,就表示连接成功,触发onopen消息,此时Web开发者就可以在此时通过send接口向服务器发送数据。否则,握手连接失败,Web应用程序会收到onerror消息,并且能知道连接失败的原因。

3.报文(与http对比差异)

request请求:

image.png

response回应:

image.png

字段说明:

image.png

4.使用 (测试url: ws://121.40.165.18:8800)

    1.创建WebSocket
    let socket = new WebSocket(url)
    
    2.WebSocket方法
    socket.send() //send(data)使用连接传输数据
    socket.close() //主动关闭WebSocket连接
    
    3.WebSocket事件
    socket.onopen //建立socket连接成功触发
    socket.onmessage //建立socket连接成功返回的数据
    socket.onerror //连接发生错误的时候触发
    socket.onclose //连接关闭的时候触发

5.心跳:ws连接成功后,开始每几秒给服务器发送数据,发送的数据,然后通过服务器返回回来,来确定链接正常运行,如果发送过去,数据一直没有返回,假如超过1min

6.异常断开重连

1.错误状态码
    1000:正常关闭	表示WebSocket连接正常关闭,没有错误发生。
    1001:终端离开	表示终端用户离开或导航到其他页面。
    1002:协议错误	表示由于协议错误,服务器无法理解客户端的请求。
    1003:数据类型错误	表示由于接收到不符合预期数据类型的数据,服务器关闭了连接。
    1005:无状态码	表示关闭帧没有包含任何状态码。这通常是由于连接丢失或意外关闭而导致的。
    1006:连接中断	表示连接意外中断,可能是由于网络问题或服务器崩溃等原因。
    1011:服务端禁止访问	表示服务器拒绝了客户端的连接请求。
    
2.非主动断开重连
    当evt.code !== 1000时候在设置定时器重连

7.结合5和6的整个WebSocket实现代码如下

<template>  
    <div>  
        <div v-html="message"></div>  
        <button @click="ws.close()">快~点我</button>  
    </div>    
</template>  
  
<script>  
import { baseUrl } from '../config/config'  //外面引入let baseUrl = ws://121.40.165.18:8800导出
export default {  
    data(){  
        return {  
            ws: null,  
            message: '',  
            timer: null,  
            timerServe: null,  
            timerRe: null
        }  
    },  
    mounted() {  
        this.initWebSocket(baseUrl)  
    },  
    methods: {  
        //初始化WebSocket
        initConnectWebSocket(url){  
            let vm = this  
            vm.ws = new WebSocket(url)  
            vm.ws.onopen = () => {  
                vm.onOpen()  
            }  
            vm.ws.onmessage = (evt) => {  
                vm.onMessage(evt)
            }  
            vm.ws.onclose = (evt) => {  
                vm.onClose(evt)  
            }  
            vm.ws.onerror = (evt) => {  
                vm.onError(evt)  
            }  
        },  
        
        //连接成功调用
        onOpen(){  
            console.log('连接成功...');  
            this.startHeart()
        },  
        
        //处理数据
        onMessage(evt) {
            this.resetHeart()  
            console.log(evt.data);  
            this.message = evt.data
        },
            
        //连接关闭触发
        onClose(evt){  
            console.log('状态码:', evt.code, '原因:', evt.reason);  
            if (evt.code !== 1000) {  
                this.reconnect()  
            } else {  
                this.timer && clearTimeout(this.timer)  
                this.timerServe && clearTimeout(this.timerServe)  
            }
        },  
        
        //连接错误触发
        onError(evt) {  
            console.log('错误信息:',evt);  
        },  

        //开启心跳  
        startHeart() {  
            this.timerRe && clearTimeout(this.timerRe)  

            this.timer = setTimeout(() => {  
                this.ws.send('hello')  
                
                this.timerServe = setTimeout(() => {  
                    this.reconnect()  
                }, 4 * 1000)  
            }, 2 * 1000)  
        }, 

        //重置心跳  
        resetHeart() {  
            this.timer && clearTimeout(this.timer)  
            this.timerServe && clearTimeout(this.timerServe)  
            this.startHeart()  
        }, 
        
        //重新连接  
        reconnect() {  
            this.timerRe && clearTimeout(this.timerRe)  

            this.timerRe = setTimeout(() => {  
                this.initWebSocket(baseUrl)  
            }, 1000)  
        }
    },  
    
    //组件销毁
    beforeDestroy() {  
        if(this.ws) {  
            this.ws.close()  
            this.ws = null  
        }  

        if(this.timer) {  
            clearTimeout(this.timer)  
            this.timer = null  
        }
        
        if(this.timerServe) {  
            clearTimeout(this.timerServe)  
            this.timerServe = null  
        }
        
        if(this.timerRe) {  
            clearTimeout(this.timerRe)  
            this.timerRe = null  
        }
    }  
}  
</script>