文章目录
- 前言
- 一、WebSocket简介
- 应用场景
- 原理
- 二、使用
- 心跳监测
- 广播消息
- 三、群聊demo
- 总结
前言
本文主要记录WebSocket的简单介绍和使用,完成群聊的demo
一、WebSocket简介
WebSocket
是一种通信协议,它通过单个TCP
连接提供全双工的通信通道。
它允许客户端和服务器之间进行实时的双向通信。
与传统的HTTP
请求不同,WebSocket
建立了客户端和服务器之间的持久连接,从而实现了高效和低延迟的通信。
要建立WebSocket
连接,客户端向服务器发送WebSocket
握手请求,服务器则以WebSocket
握手响应进行回应。
一旦连接建立,客户端和服务器都可以异步地发送消息。
WebSocket
采用基于消息的通信模型,消息以帧的形式通过WebSocket
连接发送。
这些帧可以是二进制或文本形式,具体取决于应用程序的需求。
该协议还支持消息分片、用于保持连接的ping/pong
消息以及用于优雅终止连接的关闭消息等功能。
WebSocket
得到了大多数现代Web浏览器的支持,并且可以在服务器端应用程序中使用提供WebSocket
功能的库或框架
应用场景
- 实时性要求高,如:聊天、游戏、数据可视化
- 需要频繁交换数据,如:实时协作工具、文件管理器
- 需要推送服务的应用,如:实时数据监控、通知系统
- 跨平台应用,如:桌面应用、移动端应用
它提供了比长轮询或服务器推送事件(SSE
)更高效的替代方案。
原理
- 握手阶段:客户端发送一个
HTTP
请求给服务器,请求升级为WebSocket
协议。在请求头中包含一些特殊的字段,如Upgrade
和Connection
,表明客户端希望升级到WebSocket
协议,这里也可以使用这里也可以使用WebSocket
API进行通讯API
进行通讯,实际也是发送GET请求带特殊请求头。服务器收到请求后,如果支持WebSocket
协议,则返回一个HTTP
响应,状态码为101 Switching Protocols
,表示升级成功。
- 建立连接:一旦握手成功,客户端和服务器之间建立了一个持久的双向连接。这个连接是基于
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应用程序。