在前六篇文章中,我们深入探讨了 WebSocket 的基础原理、服务端开发、客户端实现、安全实践、性能优化和测试调试。今天,让我们通过一个实战案例,看看如何将这些知识应用到实际项目中。我曾在一个大型在线教育平台中,通过 WebSocket 实现了实时互动课堂,支持了数万名师生的同时在线。
项目背景
我们要实现一个实时互动课堂系统,主要功能包括:
- 实时音视频
- 课堂互动
- 共享白板
- 实时聊天
- 课堂管理
让我们从系统设计开始。
系统架构
实现系统架构:
// app.js
const express = require('express')
const https = require('https')
const fs = require('fs')
const path = require('path')
const WebSocket = require('ws')
const Redis = require('ioredis')
const { ClusterManager } = require('./cluster-manager')
const { ConnectionPool } = require('./connection-pool')
const { MessageQueue } = require('./message-queue')
const { RoomManager } = require('./room-manager')
const { UserManager } = require('./user-manager')
const { MediaServer } = require('./media-server')
class ClassroomServer {
constructor(options = {}) {
this.options = {
port: 8080,
sslPort: 8443,
redisUrl: 'redis://localhost:6379',
mediaServer: 'localhost:8000',
...options
}
// 初始化组件
this.cluster = new ClusterManager()
this.pool = new ConnectionPool()
this.queue = new MessageQueue()
this.rooms = new RoomManager()
this.users = new UserManager()
this.media = new MediaServer(this.options.mediaServer)
this.initialize()
}
// 初始化服务器
async initialize() {
// 创建 Express 应用
this.app = express()
this.setupExpress()
// 创建 HTTPS 服务器
this.server = https.createServer({
key: fs.readFileSync('server.key'),
cert: fs.readFileSync('server.cert')
}, this.app)
// 创建 WebSocket 服务器
this.wss = new WebSocket.Server({
server: this.server,
path: '/ws'
})
// 连接 Redis
this.redis = new Redis(this.options.redisUrl)
// 设置事件处理器
this.setupEventHandlers()
// 启动服务器
await this.start()
}
// 设置 Express
setupExpress() {
// 静态文件
this.app.use(express.static('public'))
// API 路���
this.app.use('/api', require('./routes/api'))
// 错误处理
this.app.use((err, req, res, next) => {
console.error('Express error:', err)
res.status(500).json({ error: 'Internal server error' })
})
}
// 设置事件处理器
setupEventHandlers() {
// WebSocket 连接
this.wss.on('connection', (ws, req) => {
this.handleConnection(ws, req)
})
// Redis 订阅
this.redis.on('message', (channel, message) => {
this.handleRedisMessage(channel, message)
})
// 进程消息
process.on('message', (message) => {
this.handleProcessMessage(message)
})
}
// 处理 WebSocket 连接
async handleConnection(ws, req) {
try {
// 验证用户
const user = await this.users.authenticate(req)
// 创建连接
const connection = this.pool.createConnection(ws, user)
// 加入房间
const roomId = req.query.roomId
if (roomId) {
await this.rooms.joinRoom(roomId, connection)
}
// 设置消息处理器
ws.on('message', (message) => {
this.handleMessage(connection, message)
})
// 设置关闭处理器
ws.on('close', () => {
this.handleClose(connection)
})
// 发送欢迎消息
connection.send({
type: 'welcome',
data: {
user: user.toJSON(),
room: roomId ? await this.rooms.getRoomInfo(roomId) : null
}
})
} catch (error) {
console.error('Connection error:', error)
ws.close()
}
}
// 处理消息
async handleMessage(connection, message) {
try {
const data = JSON.parse(message)
// 验证消息
if (!this.validateMessage(data)) {
throw new Error('Invalid message format')
}
// 处理不同类型的消息
switch (data.type) {
case 'chat':
await this.handleChatMessage(connection, data)
break
case 'whiteboard':
await this.handleWhiteboardMessage(connection, data)
break
case '

最低0.47元/天 解锁文章
3342

被折叠的 条评论
为什么被折叠?



