在现代的网络应用中,实时通信的需求日益增加。无论是即时聊天应用、在线协作工具还是实时数据更新的仪表板,实时通信都显得至关重要。WebSocket作为一种在双向通信上表现卓越的协议,能够在客户端和服务器之间建立全双工的通信桥梁。本文将详细介绍如何在Node.js中使用WebSocket实现实时通信,并通过socket.io库实现一个聊天室示例,进一步探讨广播消息与房间管理,最后展示一个在线协作白板应用的实战案例。
1. WebSocket协议与HTTP对比
WebSocket基础概念
WebSocket是一种在单个TCP连接上提供全双工通信能力的协议。它允许客户端和服务器互相推送数据,无需重复建立连接,大大提升了交互效率和实时性。
WebSocket与HTTP的区别
- 通信模式:HTTP是请求-响应模型,每次通信都需要建立新的连接;而WebSocket建立持久连接,支持双向实时通信。
- 数据格式:HTTP通常传输文本数据,每次请求和响应都包含完整的头部信息;WebSocket可以传输文本和二进制数据,头部信息较小,减少了数据传输量。
- 应用场景:HTTP适用于传统的网页浏览、API调用等场景;WebSocket适用于实时性要求较高的场景,如在线聊天、实时游戏等。
2. 使用socket.io实现聊天室
为什么选择socket.io
Socket.IO是一个支持客户端与服务器之间实时、双向、基于事件的通信的库。它不仅简化了API接口,使得操作更容易,而且让那些不支持WebSocket协议的浏览器会将WebSocket连接自动降为Ajax连接,最大限度地保证了兼容性。
安装与配置
首先,确保你已经安装了Node.js和npm。然后,在项目根目录下运行以下命令安装socket.io:
npm install socket.io express
服务器端代码
创建一个server.js文件,用于搭建WebSocket服务器:
const socketIo = require('socket.io')
const http = require('http')
const express = require('express')
const app = express()
const server = http.createServer(app)
app.use(express.static('simple-chat'))
const IO = socketIo(server)
IO.on('connection', socket => {
console.log('一个用户连接上来了')
socket.on('message', msg => {
console.log('用户发送了一个信息过来: ' + msg)
})
socket.on('disconnect', () => {
console.log('一个用户断开连接了')
})
})
server.listen(18080, () => {
console.log('----------------- 服务器运行成功')
console.log('----------------- http://localhost:18080')
})
客户端代码
创建一个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>Simple Chat</title>
<script src="./socket.io.min.js"></script>
</head>
<body>
<hr>
<input id="msgBox" type="text" placeholder="输入要发送的消息">
<hr>
<button id="connectBtn">连接服务</button>
<hr>
<button id="sendBtn">发送消息</button>
<hr>
<button id="closeBtn">断开连接</button>
<script>
let socket = null
connectBtn.addEventListener('click', () => {
socket = io('http://localhost:18080')
})
sendBtn.addEventListener('click', () => {
if (socket) socket.emit('message', msgBox.value)
})
closeBtn.addEventListener('click', () => {
if (socket) {
socket.close()
socket = null
}
})
</script>
</body>
</html>
3. 广播消息与房间管理
房间管理
Socket.IO支持将客户端分组到“房间”,这在处理多个并发聊天室或游戏房间时非常有用。例如,你可以让用户加入特定的聊天室,并只接收该聊天室的消息。
服务器示例代码
在服务器端代码中,管理房间的加入和离开:
const socketIo = require('socket.io')
const http = require('http')
const express = require('express')
const crypto = require('crypto')
const app = express()
const server = http.createServer(app)
app.use(express.static('simple-chat'))
const IO = socketIo(server)
IO.on('connection', socket => {
console.log('一个用户连接上来了')
socket.on('join-room', obj => {
console.log(`${obj.userName} 加入聊天室 ${obj.roomName}`)
socket.join(obj.roomName)
})
socket.on('leave-room', obj => {
console.log(`${obj.userName} 离开聊天室 ${obj.roomName}`)
socket.leave(obj.roomName)
})
socket.on('message', obj => {
console.log(`${obj.userName} 在聊天室 ${obj.roomName} 发送了消息:${obj.msg}`)
socket.to(obj.roomName).emit('client-message', obj)
})
socket.on('disconnect', () => {
console.log('一个用户断开连接了')
})
})
server.listen(18080, () => {
console.log('----------------- 服务器运行成功')
console.log('----------------- http://localhost:18080')
})
客户端示例代码
在客户端代码中,让用户选择加入或离开房间:
<!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>Simple Chat</title>
<script src="./socket.io.min.js"></script>
</head>
<body>
<hr>
<label for="userName">你的名字:</label>
<input id="userName" type="text" placeholder="输入你的名字">
<hr>
<label for="roomName">你要加入的聊天室:</label>
<input id="roomName" type="text" placeholder="输入你要加入的聊天室名字">
<button id="joinBtn">加入聊天室</button>
<hr>
<ul id="infoBox"></ul>
<hr>
<input id="msgBox" type="text" placeholder="输入要发送的消息">
<hr>
<button id="sendBtn">发送消息</button>
<hr>
<button id="leaveBtn">离开聊天室</button>
<script>
let socket = null
joinBtn.addEventListener('click', () => {
socket = io('http://localhost:18080')
socket.emit('join-room', {userName: userName.value.trim(), roomName: roomName.value.trim()})
socket.on('client-message', obj => {
let li = document.createElement('li')
li.innerHTML = `${obj.userName} 发送消息:${obj.msg}`
infoBox.appendChild(li)
})
})
sendBtn.addEventListener('click', () => {
if (socket) {
socket.emit('message', {userName: userName.value.trim(), roomName: roomName.value.trim(), msg: msgBox.value.trim()})
}
})
leaveBtn.addEventListener('click', () => {
if (socket) {
socket.emit('leave-room', {userName: userName.value.trim(), roomName: roomName.value.trim()})
socket.close()
socket = null
}
})
</script>
</body>
</html>
4. 实战:在线协作白板应用
项目概述
使用Node.js、Socket.IO和Vue.js实现一个实时多人在线协作白板应用。该应用允许多个用户在同一白板上进行实时绘图和聊天。
服务器端代码
创建一个server.js文件,用于处理WebSocket连接和消息转发:
const express = require('express');
const http = require('http');
const socketIo = require('socket.io');
const app = express();
const server = http.createServer(app);
const IO = socketIo(server);
app.use(express.static('white-board'))
IO.on('connection', (socket) => {
console.log('一个用户加入了会议');
socket.on('draw', data => {
IO.emit('draw', data);
});
socket.on('message', msg => {
IO.emit('message', msg);
});
socket.on('disconnect', () => {
console.log('一个用户离开了会议');
});
});
server.listen(18080, () => {
console.log('----------------- 服务器运行成功')
console.log('----------------- http://localhost:18080')
})
前端代码
创建一个Vue项目,并添加以下组件和代码:
<!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>White Board</title>
<script src="./socket.io.min.js"></script>
<style>
#msgList,
#msgBox,
#boardNode {
display: block;
box-sizing: border-box;
width: 600px;
height: 400px;
border: solid 1px #ddd;
border-radius: 16px;
margin: 15px auto;
}
#msgList {
height: auto;
padding: 20px 10px;
}
#msgList li {
margin-left: 18px;
}
#msgBox {
height: 36px;
font-size: 14px;
color: #111;
padding: 0 10px;
}
</style>
</head>
<body>
<div>
<canvas id="boardNode" width="800" height="600"></canvas>
<ul id="msgList">
<li>接收到的信息</li>
</ul>
<input type="text" id="msgBox" placeholder="输入发送的消息..."/>
</div>
<script>
let socket = io('http://localhost:18080')
let isDrawing = false
let context = boardNode.getContext('2d')
socket.on('message', msg => {
let li = document.createElement('li')
li.innerHTML = msg
msgList.appendChild(li)
})
msgBox.addEventListener('keyup', evt => {
if (evt.keyCode == 13) {
socket.emit('message', msgBox.value.trim())
msgBox.value = ''
}
})
let x1 = 0
let y1 = 0
let x2 = 0
let y2 = 0
boardNode.addEventListener('mousedown', evt => {
isDrawing = true
context.beginPath()
x1 = evt.offsetX
y1 = evt.offsetY
context.moveTo(x1, y1)
})
boardNode.addEventListener('mousemove', evt => {
if (!isDrawing) return
x2 = evt.offsetX
y2 = evt.offsetY
context.lineTo(x2, y2)
context.stroke()
socket.emit('draw', {
x1,
y1,
x2,
y2
})
x1 = evt.offsetX
y1 = evt.offsetY
})
boardNode.addEventListener('mouseup', evt => {
isDrawing = false
context.closePath()
})
socket.on('draw', data => {
context.beginPath()
context.moveTo(data.x1, data.y1)
context.lineTo(data.x2, data.y2)
context.stroke()
})
</script>
</body>
</html>
将上述代码添加到相应的文件中,并运行项目:
npm run serve
打开多个浏览器窗口访问http://localhost:18080,你将看到多个用户可以在同一白板上进行实时绘图和聊天。
总结
本文通过WebSocket协议与HTTP的对比,介绍了WebSocket在实时通信中的优势。接着,通过socket.io库实现了一个简单的聊天室示例,并展示了如何管理广播消息和房间。最后,实战部分实现了一个在线协作白板应用,展示了WebSocket在实时多人协作场景中的应用。希望这些内容能够帮助你更好地理解和应用WebSocket技术,构建出功能丰富、性能高效的实时应用。
关注我!!🫵 持续为你带来Nodejs相关内容。