IT评测·应用市场-qidao123.com

标题: WebSocket | 背景 概念 原理 使用 优缺点及实用场景 [打印本页]

作者: 万有斥力    时间: 2024-12-25 14:19
标题: WebSocket | 背景 概念 原理 使用 优缺点及实用场景
1 背景

在 WebSocket 出现之前,为了实现推送技能,所用的技能都是轮询,轮询是指浏览器每隔一段时间向服务器发出 HTTP 哀求,服务器再返回最新的数据给客户端
常见的轮询方式分为轮询与长轮询,它们的区别如下图所示:

这种传统的模式带来很明显的缺点,即浏览器需要不绝向服务器发出哀求,然而 HTTP 哀求与相应可能会包罗较长的头部,此中真正有效的数据可能只是很少的一部分,这样会斲丧很多带宽资源。因此,HTML5 定义了 WebSocket 协议,能更好地节省服务器资源和带宽,并且能够更实时地举行通讯
2 什么是WebSocket

WebSocket 是一种网络传输协议,可在单个 TCP 毗连上举行全双工通讯,它使得客户端和服务器之间的数据交换变得更加简单,只需要完成一次握手,两者之间就可以创建持久性的毗连,并举行双向数据传输,本质上一种计算机网络应用层的协议,用来弥补 HTTP 协议在持久通讯能力上的不足
它有以下特点:

3 原理

3.1 创建毗连

在 WebSocket 开始通讯之前,通讯双方需要先辈行握手,WebSocket复用了 HTTP 的握手通道,即客户端通过 HTTP 哀求与 WebSocket 服务端协商升级协议,协议升级完成后,后续的数据交换则遵照 WebSocket 的协议
利用 HTTP 完成握手有以下利益:

3.2 交换数据

WebSocket 的每条消息可能会被切分成多个数据帧,发送端会将消息切割成多个帧发送给接收端,接收端接收消息帧,并将关联的帧重新组装成完备的消息
以下是MDN 上的示例:
  1. Client: FIN=1, opcode=0x1, msg="hello"
  2. Server: (process complete message immediately) Hi.
  3. Client: FIN=0, opcode=0x1, msg="and a"
  4. Server: (listening, newmessage containing text started)
  5. Client: FIN=0, opcode=0x0, msg="happy new"
  6. Server: (listening, payload concatenated to previous message)
  7. Client: FIN=1, opcode=0x0, msg="year!"
  8. Server: (process complete message) Happy new year to you too!
复制代码
在该示例中,客户端向服务器发送了两条消息,第一个消息在单个帧中发送,而第二个消息跨三个帧发送。当 WebSocket 的接收方收到一个数据帧时,会根据 FIN 字段值来判断是否收到消息的最后一个数据帧;利用 FIN 和 Opcode,我们就可以实现跨帧发送消息
此中 Opcode 表示操作码,它的可能值有:

具体的数据帧格式大概如下图所示,单位是比特:

3.3 维持毗连

使用 WebSocket 举行通讯,可以通过创建心跳机制来判断毗连正常没有断开或者服务是否可用,所谓心跳机制,就是定时发送一个数据包,让对方知道本身在线且正常工作,确保通讯有效;如果对方无法相应,便可以弃用旧毗连,发起新的毗连了
需要重连的场景可能包括:网络题目或者机器故障导致毗连断开、毗连没断但不可用了或者毗连对端的服务不可用
发送方 -> 接收方:ping
接收方 -> 发送方:pong
ping 、pong 的操作,对应的是 WebSocket 的两个控制帧,Opcode 分别是 0x9、0xA。比如说,WebSocket 服务端向客户端发送 ping:
  1. // ping
  2. ws.ping()
  3. // pong
  4. ws.on('pong', () => {
  5.     console.log('pong received')
  6. })
复制代码
客户端也可以发送:
  1. // 发送心跳包
  2. ws.send('heart check')
  3. // 接收响应
  4. ws.onmessage = (e) => {
  5.   const response = e.data
  6.   if (response.message === 'connection alive') {
  7.     // 重置计时器
  8.   }
  9. }
复制代码
4 WebSocket使用

以下是一个 Vue + WebSocket 使用的 demo,逐步解释每个部分是如何工作的,将从 创建毗连 到 发送消息和接收消息 全面讲解 WebSocket 的使用
4.1 创建 WebSocket 客户端

1)创建 WebSocket 实例
创建一个 WebSocket 毗连,并毗连到ws://localhost:8080 这个 WebSocket 服务器地点。这个地点指向服务器上的 WebSocket 服务,如果服务器乐成启动并运行在 8080 端口上,客户端会创建毗连
  1. const socket = new WebSocket('ws://localhost:8080')
复制代码
2)监听 WebSocket 变乱

onopen触发后,我们将毗连状态设置为“毗连已创建”,并发送一条初始化消息到服务器
  1. socket.onopen = () => {
  2.   console.log('WebSocket 连接已建立')
  3.   connectionStatus.value = '连接已建立'
  4.   socket.send('客户端已连接,发送初始化消息')
  5. }
复制代码
onmessage处理函数每次收到服务器消息时都会执行,将接收到的消息显示到页面上
  1. socket.onmessage = (event) => {
  2.   console.log('从服务器接收到消息:', event.data)
  3.   receivedMessage.value = event.data // 将收到的消息存储到响应式变量中
  4. }
复制代码
3)发送消息
通过 WebSocket 的send()方法发送消息,sendMessage()函数会在点击按钮时触发,查抄 WebSocket 是否已经毗连 (readyState === WebSocket.OPEN),如果毗连乐成,则发送消息
  1. function sendMessage() {
  2.   if (socket.readyState === WebSocket.OPEN) {
  3.     const message = '这是客户端发送的消息'
  4.     socket.send(message)
  5.     console.log('已发送消息:', message)
  6.   } else {
  7.     console.log('WebSocket 连接未打开,无法发送消息')
  8.   }
  9. }
复制代码
4)状态消息
使用 ref 来处理 WebSocket 毗连的状态

  1. const connectionStatus = ref('未连接')
  2. const receivedMessage = ref('等待服务器消息...')
复制代码
团体 vue 代码如下:
  1. <template>  <div>    <h2>WebSocket 使用示例</h2>    <!-- 显示当前毗连状态 -->    <p>毗连状态: {{ connectionStatus }}</p>    <!-- 按钮触发发送消息 -->    <button @click="sendMessage">发送消息</button>    <!-- 显示从服务器接收到的消息 -->    <p><strong>从服务器接收到的消息:</strong> {{ receivedMessage }}</p>  </div></template><script setup>import { ref } from 'vue'// 设置 WebSocket 相干状态const connectionStatus = ref('未连接')
  2. const receivedMessage = ref('等待服务器消息...')
  3. // 创建 WebSocket 实例,毗连到 WebSocket 服务器// 确保 WebSocket 服务器已经在 8080 端口上运行const socket = new WebSocket('ws://localhost:8080')
  4. // 监听 WebSocket 毗连打开变乱socket.onopen = () => {
  5.   console.log('WebSocket 连接已建立')
  6.   connectionStatus.value = '连接已建立'
  7.   socket.send('客户端已连接,发送初始化消息')
  8. }
  9. ;// 监听 WebSocket 接收到消息变乱socket.onmessage = (event) => {
  10.   console.log('从服务器接收到消息:', event.data)
  11.   receivedMessage.value = event.data // 将收到的消息存储到响应式变量中
  12. }
  13. ;// 监听 WebSocket 关闭变乱socket.onclose = () => {  console.log('WebSocket 毗连已关闭')  connectionStatus.value = '毗连已关闭'};// 监听 WebSocket 错误变乱socket.onerror = (error) => {  console.log('WebSocket 出现错误:', error)  connectionStatus.value = '毗连错误'};// 发送消息的函数function sendMessage() {
  14.   if (socket.readyState === WebSocket.OPEN) {
  15.     const message = '这是客户端发送的消息'
  16.     socket.send(message)
  17.     console.log('已发送消息:', message)
  18.   } else {
  19.     console.log('WebSocket 连接未打开,无法发送消息')
  20.   }
  21. }
  22. </script><style scoped>h2 {  color: #42b983;}button {  margin-top: 10px;  padding: 10px;  background-color: #42b983;  color: white;  border: none;  cursor: pointer}button:hover {  background-color: #36a372;}</style>
复制代码
4.2 运行 WebSocket 服务器

以下是一个简单的 WebSocket 服务器,使用 Node.js 和 ws 库
1)安装 ws 包
  1. npm install ws
复制代码
2)WebSocket 服务器代码
  1. // server.js
  2. const WebSocket = require('ws')
  3. // 创建 WebSocket 服务器,监听 8080 端口
  4. const wss = new WebSocket.Server({ port: 8080 })
  5. // 当有客户端连接时触发
  6. wss.on('connection', (ws) => {
  7.   console.log('客户端已连接')
  8.   // 向客户端发送一条消息
  9.   ws.send('欢迎连接 WebSocket 服务器!')
  10.   // 监听客户端发送的消息
  11.   ws.on('message', (message) => {
  12.     console.log('收到来自客户端的消息:', message)
  13.     // 将收到的消息原封不动地返回给客户端
  14.     ws.send(`服务器已收到: ${message}`)
  15.   });
  16.   // 处理连接关闭
  17.   ws.on('close', () => {
  18.     console.log('客户端已断开连接')
  19.   });
  20. });
  21. console.log('WebSocket 服务器正在监听端口 8080...')
复制代码
3)启动 WebSocket 服务器
在 Node.js 项目对应的目录中,运行以下命令来启动服务器,xxx是该 js 文件名
  1. node xxx.js
复制代码
4.3 运行 Vue 项目

运行 Vue 项目后,在浏览器中打开 Vue 页面后,大致毗连流程如下:
1)WebSocket 毗连的状态:未毗连 → 毗连已创建
2)点击按钮可以发送消息到 WebSocket 服务器
3)从 WebSocket 服务器接收到的相应消息,展示到页面中

5 优缺点及实用场景

长处:

缺点:

实用场景:


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 IT评测·应用市场-qidao123.com (https://dis.qidao123.com/) Powered by Discuz! X3.4