前言
之前遇到过需要即时通讯的场景,刚开始使用的是通过轮询的方式,定时器3秒向服务器请求一次数据,后面发现如果在手机端长时间打开使用此功能的页面,可能会发生手机发热,甚至卡顿的现象。最后改用webSocket,可以实现全双工通信,让服务器主动向客户端发送请求。
接下来先介绍一下即时通信的实现方法?
-
轮询(Polling):
- 工作原理:客户端定时向服务器发送请求,询问是否有新数据可用。如果服务器有新数据,返回数据;如果没有,服务器返回空响应。客户端收到响应后立即再次发送请求,形成周期性的轮询过程。
- 优点:实现简单,大部分浏览器和服务器都支持。
- 缺点:频繁的请求和响应会导致不必要的网络开销,降低性能和效率。
- 适用场景:适用于数据更新频率不高且实时性要求不高的场景。
-
长轮询(Long Polling):
- 工作原理:客户端发送请求给服务器,服务器不立即返回响应,而是将请求挂起,等待有新数据时再返回响应。一旦客户端收到响应,立即再次发送请求,形成新的挂起请求。
- 优点:相较于轮询,减少了不必要的网络请求,降低了网络开销。
- 缺点:服务器需要维护大量挂起的请求,占用资源较多,不适用于高并发场景。
- 适用场景:适用于数据更新不频繁,但要求实时性相对较高的场景。
-
WebSocket:
- 工作原理:WebSocket 是一种全双工通信协议,通过建立持久性的连接,客户端和服务器可以随时发送和接收消息。连接建立后,双方可以直接发送消息,不需要频繁的握手过程。
- 优点:实现实时通信,降低了不必要的网络开销,性能高,支持跨域通信。
- 缺点:需要服务器和客户端都支持 WebSocket 协议。
- 适用场景:适用于需要实时通信的场景,如实时聊天、在线游戏等。
-
Server-Sent Events(SSE):
- 工作原理:SSE 是一种单向通信协议,允许服务器向客户端发送数据,但客户端不能向服务器发送数据。客户端通过
EventSource
对象订阅服务器的事件流,一旦有新数据可用,服务器会自动发送数据给客户端。 - 优点:实现简单,不需要像 WebSocket 那样进行双向握手,适用于服务器向客户端推送数据。
- 缺点:只支持单向通信,不适用于客户端向服务器发送请求。
- 适用场景:适用于服务器主动向客户端推送实时数据的场景,如推送通知、实时监控等。
- 工作原理:SSE 是一种单向通信协议,允许服务器向客户端发送数据,但客户端不能向服务器发送数据。客户端通过
前端如何使用 WebSocket?
在前端中使用 WebSocket 非常简单,首先需要在浏览器中创建一个 WebSocket 对象,然后通过该对象与服务器建立连接。一旦连接建立成功,前端可以通过发送和接收消息来实现与服务器的实时通信。
1. 创建 WebSocket 对象
在 JavaScript 中,可以通过以下代码创建 WebSocket 对象:
const socket = new WebSocket('ws://example.com'); // 根据实际情况替换为服务器的 WebSocket 地址
在上述代码中,我们创建了一个 WebSocket 对象,传入服务器的 WebSocket 地址作为参数。WebSocket 地址的协议可以是 ws
(未加密)或 wss
(加密)。
2. 监听事件
一旦 WebSocket 连接建立成功,就可以通过监听事件来处理连接状态和消息的收发。
socket.onopen = () => {
console.log('WebSocket连接已建立');
};
socket.onmessage = event => {
const message = event.data;
console.log('收到消息:', message);
};
socket.onclose = () => {
console.log('WebSocket连接已关闭');
};
socket.onerror = error => {
console.error('WebSocket连接错误:', error);
};
在上述代码中,我们监听了 onopen
事件(连接建立)、onmessage
事件(收到消息)、onclose
事件(连接关闭)、onerror
事件(连接错误)。每当相应的事件触发时,我们通过回调函数来处理相应的逻辑。
3. 发送和接收消息
一旦 WebSocket 连接建立成功,就可以通过 send()
方法来发送消息,同时通过 onmessage
事件来接收消息。
// 发送消息
socket.send('Hello, WebSocket!');
// 接收消息在上面的监听代码中已经处理
以上代码演示了如何在前端中创建 WebSocket 连接、发送和接收消息。当服务器和客户端建立连接后,它们可以随时通过 send()
方法和 onmessage
事件来实现实时通信。
案例
实现一个简易的聊天功能
1.创建一个文件夹
2.初始化
npm init -y
npm install websocket
3.创建websocket服务端,命名为server.js
const websocket=require("websocket").server
const http=require('http');
const httpServer = http.createServer().listen(8080, ()=>{
console.log('cyl: ','http://localhost:8080');
})
const websocketServer = new websocket({
httpServer: httpServer,
autoAcceptConnections: false
})
const conArr = []
websocketServer.on('request', function(request) {
// 这就是一次客户端发送的消息
// websocket 需要将这个链接保存起来
// 只要客户端和服务器没有断开,这个链接必须在
// 客户端与服务端的通信都是从这个链接上通信
const connection = request.accept()
// 每次接收一个链接,将它存放在数组里面
conArr.push(connection)
console.log(connection)
// 监听客户端发送的消息
connection.on('message', function(message) {
console.log(message);
// 发送消息给客户端(广播到各个客户端)
// 后面加上 utf8Data 编码
// 要将所有的链接全部发出去,才可以让每个客户端接收到其他传来的数据
for(let i = 0; i < conArr.length; i++) {
conArr[i].send(message.utf8Data)
}
})
})
4.创建传送给客户端的文件index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- 需要一进入浏览器就要建立链接 -->
<!-- 点击按钮发送消息给服务器 -->
输入姓名:<input type="text" id="uName">
<br>
输入消息:<input type="text" id="context">
<button id="btn"> 点击发送消息 </button>
<div id="charRoom"></div>
<script>
// 用户名
const uName = document.getElementById('uName')
// 文本框内容
const context = document.getElementById('context')
// 点击按钮
const btn = document.getElementById('btn')
// 要显示聊天室的区域
const charRoom = document.getElementById('charRoom')
// 实例化 websocket
// 必须加 'ws://localhost:8080' ws 协议,后面是开启的服务端接口
const websocket = new WebSocket('ws://localhost:8080')
// 打开事件
websocket.onopen = function() {
// 获取当前链接的状态
// 1 是建立了链接
console.log(websocket.readyState);
}
// 点击发送消息的事件
btn.onclick = function() {
// 将用户名和要发送的内容放在一个对象中,一起传送给后端
const values = {
uName: uName.value,
context: context.value
}
// 清空文本框的内容
uName.value = ''
context.value = ''
// 通过 websocket发送消息
websocket.send(JSON.stringify(values))
}
// 接收服务器返回的消息
websocket.onmessage = function(data) {
console.log("服务器返回的数据",data)
// 服务器返回过来的聊天信息
const chatS = JSON.parse(data.data)
// 添加到页面上
charRoom.innerHTML += `
<strong>${chatS.uName}:</strong>
<span>${chatS.context}</span>
<br />
`
}
// 服务器断开连接,客户端会触发
websocket.onclose = function() {}
</script>
</body>
</html>
4.启动服务端
node server.js
服务启动成功