websocket是网页端实时判题系统的核心技术,通过全双工长连接实现代码提交、判题结果与运行状态的毫秒级同步;前后端通过带房间id的url建立连接并绑定身份,提交后校验并分发至沙箱,结果经redis pub/sub推送,前端依submit_id动态渲染,同时通过心跳、重连、序号校验等机制保障可靠性。

WebSocket 是实现网页端实时判题系统的核心技术,它能建立浏览器与服务器之间的全双工长连接,让代码提交、判题结果、运行状态(如“编译中”“正在运行”“AC”“WA”)毫秒级同步到所有参赛者页面,无需轮询或 Server-Sent Events 的单向限制。
一、前后端 WebSocket 连接建立与身份绑定
用户进入比赛页面时,前端通过 new WebSocket('wss://your-domain.com/ws?room=contest-2024') 发起连接,并在 URL 中携带房间 ID 或用户 Token。服务端(如 Node.js + ws 库 / Python + FastAPI WebSockets)需解析参数,将 socket 实例与用户 ID、题目 ID、比赛房间关联起来,存入内存 Map 或 Redis 哈希表。例如:
– 用户 A 提交题号 #3 → 服务端记录 {'userA': {'room': 'contest-2024', 'current_problem': 3}}
– 后续判题结果推送时,只广播给同房间且关注该题的客户端。
二、代码提交与判题任务分发流程
前端监听表单提交,序列化语言、代码、输入样例(可选)后,用 socket.send(JSON.stringify({type: 'submit', lang: 'python3', code: 'print(1+1)', problem_id: 5})) 发送;服务端收到后不做响应等待,立即:
– 校验代码长度、语言白名单、防注入(如过滤 os.system、__import__ 等危险调用)
– 将任务推入消息队列(如 Redis List 或 RabbitMQ),由独立判题沙箱服务消费
– 向该用户 socket 返回 {type: 'status', status: 'pending', submit_id: 'sub_abc123'},前端据此切换按钮为“判题中”并禁用重复提交
三、实时判题结果推送与前端渲染
沙箱执行完后(含编译、运行、时间/内存限制检测、样例比对),判题服务通过内部通信(如 Redis Pub/Sub)通知 WebSocket 服务,后者查出对应用户 socket 并推送结构化结果:{type: 'result', submit_id: 'sub_abc123', status: 'AC', time_ms: 42, memory_kb: 3240, testcases: [{id: 1, status: 'AC'}, {id: 2, status: 'WA', output: '2', expected: '3'}]}
前端用 submit_id 匹配 DOM 元素(如 <div id="result-sub_abc123">),动态更新状态徽章、耗时标签,并展开测试点详情。若多人同题,可加“本题最新 AC”全局提示栏,用 <code>socket.onmessage 统一处理。
四、异常处理与连接可靠性保障
WebSocket 易受网络抖动影响,需主动兜底:
– 前端设置 socket.onclose = () => setTimeout(() => connect(), 3000) 自动重连,带重连次数限制与退避策略
– 服务端启用心跳(每 30 秒 send {type: 'ping'}),客户端回 {type: 'pong'},超时未响应则断开并触发重连
– 提交后若 15 秒未收到 status 消息,前端显示“判题延迟,请稍候”,同时发起一次 {type: 'query_status', submit_id: '...'} 查询请求(走 HTTP 接口兜底)
– 所有推送消息带 seq 序号,前端丢弃乱序或重复消息,防止 UI 错乱











