网络-WebSocket


文章目录

  • 前言
  • 一、WebSocket简介
    • 应用场景
    • 原理
  • 二、使用
    • 心跳监测
    • 广播消息
  • 三、群聊demo
  • 总结


前言

本文主要记录WebSocket的简单介绍和使用,完成群聊的demo


一、WebSocket简介

WebSocket是一种通信协议,它通过单个TCP连接提供全双工的通信通道。
它允许客户端和服务器之间进行实时的双向通信。
与传统的HTTP请求不同,WebSocket建立了客户端和服务器之间的持久连接,从而实现了高效和低延迟的通信。

要建立WebSocket连接,客户端向服务器发送WebSocket握手请求,服务器则以WebSocket握手响应进行回应。
一旦连接建立,客户端和服务器都可以异步地发送消息。

WebSocket采用基于消息的通信模型,消息以帧的形式通过WebSocket连接发送。
这些帧可以是二进制或文本形式,具体取决于应用程序的需求。
该协议还支持消息分片、用于保持连接的ping/pong消息以及用于优雅终止连接的关闭消息等功能。
WebSocket得到了大多数现代Web浏览器的支持,并且可以在服务器端应用程序中使用提供WebSocket功能的库或框架

应用场景

  • 实时性要求高,如:聊天、游戏、数据可视化
  • 需要频繁交换数据,如:实时协作工具、文件管理器
  • 需要推送服务的应用,如:实时数据监控、通知系统
  • 跨平台应用,如:桌面应用、移动端应用

它提供了比长轮询或服务器推送事件(SSE)更高效的替代方案。

原理

  • 握手阶段:客户端发送一个HTTP请求给服务器,请求升级为WebSocket协议。在请求头中包含一些特殊的字段,如UpgradeConnection,表明客户端希望升级到WebSocket协议,这里也可以使用这里也可以使用WebSocket API进行通讯API进行通讯,实际也是发送GET请求带特殊请求头。服务器收到请求后,如果支持WebSocket协议,则返回一个HTTP响应,状态码为101 Switching Protocols,表示升级成功。

网络-WebSocket_第1张图片

  • 建立连接:一旦握手成功,客户端和服务器之间建立了一个持久的双向连接。这个连接是基于TCP的,可以实现全双工通信,即客户端和服务器可以同时发送和接收消息。
    数据传输:客户端和服务器可以通过WebSocket连接发送和接收消息。消息以帧的形式进行传输,可以是二进制数据或文本数据。帧包含了一些控制信息,如消息类型、消息长度等。客户端和服务器可以异步地发送和接收消息,实现实时的双向通信。
  • 保持连接:WebSocket连接是持久的,不会像传统的HTTP请求那样每次都需要重新建立连接。为了保持连接的活跃状态,客户端和服务器可以定期发送心跳消息,以确保连接不会断开。
  • 关闭连接:当客户端或服务器希望关闭WebSocket连接时,可以发送一个关闭帧。接收到关闭帧的一方会响应一个关闭帧,然后双方的连接会被正常关闭。

二、使用

  • 创建ws对象
const ws = new WebSocket('ws://localhost:8080');
  • 监听连接成功
ws.onopen = function () {
            console.log('已连接')
        }
  • 发送消息
ws.send('发送的消息')
  • 接收消息
 ws.onmessage = function (e) {
            console.log(e.message)
        }
  • 断开连接
ws.close()
  • 监听断开连接
ws.onclose = function() {
            console.log('WebSocket连接已关闭');
        };
  • 监听连接错误
ws.onerror = function(error) {
            console.error('WebSocket连接发生错误:', error);
        };
  • 事件监听器
    WS是可以添加事件监听器的,如open、message、close、error等与属性效果是一致的。
 ws.addEventListener('open',function (event) {
            console.log('连接成功')
            isConnected = true;
        })
ws.addEventListener('message',(e)=>{
            let li = document.createElement('li')

            let data = JSON.parse(e.data)
            if (data.type == 2){
                li.innerText = data.message
                list.appendChild(li)
            }else {
                console.log(data.message)
            }
        })

心跳监测

socket连接在长时间不使用、网络波动、弱网状况下有可能断开连接,需要进行心跳监测来保证连接存活。在断开连接时,实现重连,在进行心跳消息发送时,客户端需要将心跳监测信息过滤掉。

 let heartInreaval = null
    const heartCheck = () =>{
        // 等于open 发送心跳
        if (socket.readyState === ws.OPEN){
            socket.send(JSON.stringify({
                type:state.HEART,
                message:'心跳检测'
            }))
        }else {
            clearInterval(heartInreaval)
        }
    }
    setInterval(heartCheck,5000)

广播消息

在后端直接使用send发送消息只能针对点对点的,不能将消息发送给全部连接,需要使用clients属性遍历发送,达到广播的效果

 // 广播消息
        wss.clients.forEach((client)=>{
            client.send(JSON.stringify({
                type:state.MESSAGE,
                message:e.toString()
            }))
        })

三、群聊demo

前端:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div>
    <ul id="list"></ul>
    <input type="text" id="input">
    <button id="send">发送</button>
    <button id="stop">断开连接</button>
</div>
</body>
<script>
    // 连接状态
    let isConnected = false;
    let input = document.getElementById('input')
    let btn = document.getElementById('send')
    let list = document.getElementById('list')
    let stop = document.getElementById('stop')
    function connectWebSocket() {
        // 创建ws实例
        const ws = new WebSocket('ws://localhost:8080');
        // 监听连接成功
        ws.addEventListener('open',function (event) {
            console.log('连接成功')
            isConnected = true;
        })
        btn.addEventListener('click',function () {
            if (input.value){
                // send发送消息
                ws.send(input.value)
                input.value = ''
            }
        })
        ws.addEventListener('message',(e)=>{
            let li = document.createElement('li')

            let data = JSON.parse(e.data)
            if (data.type == 2){
                li.innerText = data.message
                list.appendChild(li)
            }else {
                console.log(data.message)
            }
        })
        //断开连接
        stop.addEventListener('click',()=>{
            ws.close()
        })
        // ws.onopen = function () {
        //     console.log('已连接')
        // ws.send('发送的消息')
        // ws.onmessage = function (e) {
        //     console.log(e.message)
        // }
        // }
        ws.onclose = function() {
            console.log('WebSocket连接已关闭');
            isConnected = false;
            // 进行重连
            reconnect();
        };

        // 监听WebSocket连接发生错误事件
        ws.onerror = function(error) {
            console.error('WebSocket连接发生错误:', error);
            isConnected = false;
            // 进行重连
            reconnect();
        };
    }
    // 重连函数
    function reconnect() {
        if (!isConnected) {
            console.log('尝试重新连接...');
            setTimeout(connectWebSocket, 5000);
        }
    }
    connectWebSocket()

</script>
</html>

后端:这里使用Node

//安装 ws
const ws =require('ws')
// 创建socket服务
const wss = new ws.Server({port:8080},()=>{
    console.log('socket服务启动成功')
})

//心跳枚举
const state = {
    HEART:1,
    MESSAGE:2
}

// 监听客户端连接
wss.on('connection',(socket)=>{
    //监听客户端消息
    console.log('客户端连接成功')
    socket.on('message',(e)=>{
        console.log(e.toString())
        // 广播消息
        wss.clients.forEach((client)=>{
            client.send(JSON.stringify({
                type:state.MESSAGE,
                message:e.toString()
            }))
        })
    })
    let heartInreaval = null
    const heartCheck = () =>{
        // 等于open 发送心跳
        if (socket.readyState === ws.OPEN){
            socket.send(JSON.stringify({
                type:state.HEART,
                message:'心跳检测'
            }))
        }else {
            clearInterval(heartInreaval)
        }
    }
    setInterval(heartCheck,5000)
})


总结

WebSocket通过握手阶段建立持久的双向连接,然后通过帧的方式传输数据,实现实时的双向通信。它相比传统的HTTP请求具有更低的延迟和更高的效率,适用于需要实时更新的Web应用程序。

你可能感兴趣的:(网络,网络,websocket,网络协议)