
VMUX信令流程揭秘不靠WebSocketSSERedis Pub/Sub如何驱动WebRTC握手【免费下载链接】vmuxSecure P2P text, audio and video chats in your browser.项目地址: https://gitcode.com/gh_mirrors/vm/vmuxVMUX 是一款纯浏览器实现的 WebRTC 应用支持 P2P 加密文字、语音和视频通话。它最特别的地方在于信令层没有用最常见的 WebSocket而是用 SSEServer-Sent Events Redis Pub/Sub 这套组合来驱动整个 WebRTC 握手。本文带你拆解这条信令链路是怎么转起来的 为什么不用 WebSocket很多 WebRTC 项目默认上 WebSocket 做信令因为它是全双工的。但 SSE 有一个天然优势一条 HTTP 长连接就能实现服务端→客户端的持续推送浏览器原生支持自动重连还天然穿透大多数代理和防火墙。VMUX 的客户端→服务端方向只需要简单的POST请求就够了信令消息本身不大服务端→客户端方向用 SSE 推送。Redis Pub/Sub 则充当服务端内部的消息总线让任意一台 Node 进程都能把消息投递到目标用户正挂着的那条 SSE 连接上。信令架构全景整体链路可以概括为四步客户端用EventSource打开一条 SSE 通道服务端为该用户维护一个 Redis 订阅客户端对方发来信令时任意请求端POST到服务端服务端redis.publish到对应用户频道Redis 把消息推给该用户的 SSE 连接逐字节写回浏览器。浏览器A ──POST /signal/:id──▶ Express ──publish──▶ Redis Pub/Sub ──subscribe──▶ Express ──SSE──▶ 浏览器B第一步客户端拨入 SSE 通道客户端的信令接收端封装在 sse.coffee 中核心就是一行source new EventSource(sse_path) # sse_path 形如 /sse/profile-xxx它监听open、error、signal、ack、otr等命名事件收到后通过 Backbone 事件机制分发给应用各处。第二步SSE 长连接如何保持不断服务端入口在 app.coffee/sse/:res路由做了三件关键的事返回Content-Type: text/event-stream、Cache-Control: no-cache并把 socket 超时设为无限每 15 秒写一个空行做心跳防止中间层掐断空闲连接每收到一条 Redis 消息就按 SSE 协议写出retry: 500、event:和data:三行retry告诉浏览器断线后 500ms 自动重连。res.write retry: 500\n res.write event: #{msg.event}\n res.write data: #{JSON.stringify(msg.payload)}\n\n第三步Redis Pub/Sub 充当消息总线VMUX 每个用户都有一条专属的发布/订阅频道命名规则是user:userId。为了让 SSE 连接能收到消息服务端在 app.coffee 中维护了一个Redis 客户端池每个 SSE 连接对应一个池内客户端该客户端订阅目标用户的user:频道以及其好友列表对应的channel:频道好友列表从 Redis 集合friends:uuid中读取所以好友上线时对方也能第一时间感知。上行方向同样轻描淡写app.coffee 中提供了几个通用入口路由用途POST /signal/:id投递 WebRTC 信令offer/answer/candidate 等POST /otr/:id投递 OTR 加密消息密钥协商与信令本身POST /s/:evt/:id通用事件如ack回执、online状态它们的实现都是同一句话redis.publish user:目标id, JSON.stringify(msg)。至此SSE Redis Pub/Sub 的下行通道和 POST 的上行通道闭环了。WebRTC 握手是如何完成的信道通了之后真正的 WebRTC 握手在客户端模型里发生核心逻辑在 user.coffee 和 peer_connection.coffee1. OTR 密钥协商先行。handshake()调用sendQueryMsg()双方先完成 OTR 的 AKE密钥协商。VMUX 的信令消息全部走 OTR 加密通道服务器只是哑管道看不到任何信令内容 2. 先建数据通道Data PC。AKE 成功后客户端创建DPCData PeerConnection并调用initiate()createOffer→setLocalDescription→ 把 SDP 通过sendSignal发出。对端在 OTR 的ui事件里收到offer调用processOffer()生成 answer 回传。3. 交换 ICE 候选。onicecandidate每产生一个候选就发一条candidate类型信令对端addIceCandidate汇入。VMUX 同时配置了 STUN/TURN 服务器见 peer_connection.coffee保证 NAT 两侧也能打洞成功。4. 媒体通话在数据通道之上发起。文字聊天直接走 DataChannel要发起视频/语音通话时先在数据通道里发requestVideo/videoOffer之类的消息协商再分别创建VPC视频或APC音频PeerConnection重复一遍 offer/answer/candidate 流程。挂断时发bye信号并关闭连接。三种 PeerConnection 的分工一览类型用途音频视频DPC数据通道承载文字聊天与通话协商❌❌VPC视频通话✅✅APC语音通话✅❌这套方案对新手有什么启发SSE 足够轻量单向推送场景下SSE 比 WebSocket 实现更简单还自带重连retry字段Redis Pub/Sub 解决多进程问题当 Node 应用水平扩展为多实例时A 进程的 POST 需要精准投到 B 进程上挂着的那条 SSE 连接Redis 发布/订阅是标准答案信令与媒体分离VMUX 里服务器只转发加密后的信令字节媒体流完全 P2P 直达服务器带宽成本几乎为零。想深入源码的话建议按这个顺序阅读服务端 app.coffee、客户端信令封装 sse.coffee、WebRTC 连接管理 peer_connection.coffee、信令与 OTR 交互 user.coffee环境配置Redis 地址、端口等见 environments.coffee。理解完这条 SSE → Redis → SSE 的闭环你就能明白WebRTC 的握手从来不是单一技术而是可靠的信令运输标准的 SDP/ICE 交换两部分VMUX 给前者提供了相当优雅的答案 【免费下载链接】vmuxSecure P2P text, audio and video chats in your browser.项目地址: https://gitcode.com/gh_mirrors/vm/vmux创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考