在远程考试场景中,实时监控和双向通信是确保考试公平性的核心需求。本文将分享一个基于 WebRTC 和 WebSocket 技术的在线监考系统实现方案,包含前端学生端、监考端及后端服务代码,实现了视频监控、实时消息、作弊标记等核心功能。基本无任何延迟,经过改造以及二次开发后可做视频会议等应用。
系统架构设计
该系统采用 "前端实时通信 + 后端信令转发" 的架构:


- 前端:使用 WebRTC 实现点对点视频流传输,WebSocket 处理信令交换和消息通信
- 后端:基于 Spring Boot 实现 WebSocket 服务,负责会话管理、信令转发和学生状态维护
- 核心技术:WebRTC(实时音视频)、WebSocket(长连接通信)、Spring Boot(后端服务)
核心功能实现
-
实时视频监控
-
学生端通过
getUserMedia获取摄像头 / 麦克风流,通过 WebRTC 推送到监考端 -
监考端支持多宫格显示,可对单个视频进行全屏、声音控制和重新连接操作
-
代码关键点:
javascript
运行
localStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true }); function createStudentVideo(student) { const video = document.createElement('video');
-
-
分级消息通信
-
支持三类消息发送:全体学生、指定年级、指定班级
-
消息记录实时展示,包含时间戳和发送对象
-
代码关键点:
javascript
运行
const target = document.getElementById('targetSelect').value; ws.send(JSON.stringify({ type: 'INVIGILATOR_MSG', to: target, // 支持ALL/GRADE_x/CLASS_x_x
-
-
作弊标记与警告
-
监考端可标记学生作弊并填写原因
-
学生端实时收到作弊警告提示
-
代码关键点:
javascript
运行
function markCheat(studentId) { const reason = prompt(`请输入标记原因:`); ws.send(JSON.stringify({ studentId: studentId, if (data.type === 'CHEAT_MARK') { alert(`警告:您已被标记为作弊!原因:${data.content}`);
-
-
WebRTC 信令交互
-
采用标准 SDP 协商流程(OFFER-ANSWER)
-
使用 STUN 服务器进行 NAT 穿透
-
后端负责信令转发,支持会话容错处理
-
代码关键点:
javascript
运行
const pc = new RTCPeerConnection({ iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] pc.onicecandidate = (event) => { type: 'ICE_CANDIDATE', data: event.candidate
-
后端核心逻辑
-
WebSocket 会话管理
-
维护学生和监考端的在线状态
-
按考试 ID、年级、班级分组管理学生
-
代码关键点:
java
运行
public void addStudent(StudentInfo student) { onlineStudents.put(student.getStudentId(), student); String groupKey = getGroupKey(student.getInvigilateId(), student.getGradeId(), student.getClassId()); studentGroupMap.computeIfAbsent(groupKey, k -> new ArrayList<>()).add(student);
-
-
信令转发服务
-
处理 WebRTC 信令(OFFER/ANSWER/ICE_CANDIDATE)的转发
-
实现容错机制,确保信令可靠送达
-
代码关键点:
java
运行
private void forwardSignaling(SignalingData signaling) throws IOException { WebSocketSession targetSession = findSessionById(signaling.getTo()); if (targetSession != null) { sendToSession(targetSession, signaling);
-
本文使用 文章同步助手 同步