当前位置: 首页 > news >正文

webrtc peerconnection_server 模块介绍

peerconnection_server是webrtc一个简单的信令服务器示例,它位于 src/examples/peerconnection/server/ 目录下。它的主要目的是配合 peerconnection_client(另一个示例客户端)使用,演示两个 WebRTC 对等端(Peer)如何通过一个中间服务器交换建立连接所需的元数据(SDP 和 ICE Candidates),从而完成 P2P 握手。

• 它仅用于学习和测试 WebRTC 的信令流程。
• 它不支持大规模并发、没有身份验证、没有加密(HTTPS/WSS)、功能非常有限。
• 在实际产品中,你需要使用专业的信令服务器(如基于 WebSocket 的 Node.js/Go/Python 服务,或使用 SIP 协议的服务)。

一、核心功能

peerconnection_server 的主要职责是消息中转。它不处理任何媒体数据(音频/视频),只处理文本信令。

1.1. 用户注册与发现:

• 客户端启动时连接到服务器并注册一个名字(例如 "Alice")。
• 服务器维护一个在线用户列表。
• 当新用户加入或旧用户离开时,服务器会通知所有其他在线用户更新他们的成员列表。

1.2. 消息路由:

• 当 Alice 想呼叫 Bob 时,她通过服务器发送一条消息给 Bob。
• 服务器根据 Bob 的名字或 ID,将消息转发给 Bob 的连接。

1.3. 支持的信令类型:

• SDP Offer/Answer: 用于协商媒体能力(编解码器、分辨率等)。
• ICE Candidates: 用于网络穿透,交换双方的网络地址信息。

二、实现架构

该服务器是一个单线程、非阻塞 I/O 的 HTTP 服务器。

2.1. 网络层:

• 使用原生 BSD Socket API(跨平台封装在 SocketBase, DataSocket, ListeningSocket 中)。
• 使用 select() (Linux/Mac) 或 WSAPoll (Windows)进行 I/O 多路复用,在一个线程中同时处理多个客户端连接。

2.2. 应用层协议:

• 基于 HTTP/1.1。
• 使用 长轮询(Long-Polling) 机制来实现服务器向客户端的“推送”。
• 客户端发送一个 /wait 请求。
• 服务器挂起该请求,直到有发给该客户端的消息到达,或者超时。
• 一旦有消息,服务器立即响应 HTTP 200 OK 并带上消息体。
• 客户端收到后立即发起下一个 /wait 请求。

2.3. 核心类:

• ChannelMember:

这个类代表一个已连接到信令服务器的特定用户/客户端。每个浏览器标签页或应用程序实例在服务器上都有一个对应的 ChannelMember 对象。


• PeerChannel :

这个类代表整个聊天室或信令房间。它管理所有当前连接的 ChannelMember。在示例代码中,通常只有一个全局的 PeerChannel 实例,所有用户都在同一个“房间”里。

// Represents a single peer connected to the server. class ChannelMember { public: explicit ChannelMember(DataSocket* socket); ~ChannelMember(); bool connected() const { return connected_; } int id() const { return id_; } void set_disconnected() { connected_ = false; } bool is_wait_request(DataSocket* ds) const; const std::string& name() const { return name_; } bool TimedOut(); std::string GetPeerIdHeader() const; bool NotifyOfOtherMember(const ChannelMember& other); // Returns a string in the form "name,id\n". std::string GetEntry() const; void ForwardRequestToPeer(DataSocket* ds, ChannelMember* peer); void OnClosing(DataSocket* ds); void QueueResponse(const std::string& status, const std::string& content_type, const std::string& extra_headers, const std::string& data); void SetWaitingSocket(DataSocket* ds); protected: struct QueuedResponse { std::string status, content_type, extra_headers, data; }; DataSocket* waiting_socket_; int id_; bool connected_; time_t timestamp_; std::string name_; std::queue<QueuedResponse> queue_; static int s_member_id_; }; // Manages all currently connected peers. class PeerChannel { public: typedef std::vector<ChannelMember*> Members; PeerChannel() {} ~PeerChannel() { DeleteAll(); } const Members& members() const { return members_; } // Returns true if the request should be treated as a new ChannelMember // request. Otherwise the request is not peerconnection related. static bool IsPeerConnection(const DataSocket* ds); // Finds a connected peer that's associated with the |ds| socket. ChannelMember* Lookup(DataSocket* ds) const; // Checks if the request has a "peer_id" parameter and if so, looks up the // peer for which the request is targeted at. ChannelMember* IsTargetedRequest(const DataSocket* ds) const; // Adds a new ChannelMember instance to the list of connected peers and // associates it with the socket. bool AddMember(DataSocket* ds); // Closes all connections and sends a "shutting down" message to all // connected peers. void CloseAll(); // Called when a socket was determined to be closing by the peer (or if the // connection went dead). void OnClosing(DataSocket* ds); void CheckForTimeout(); protected: void DeleteAll(); void BroadcastChangedState(const ChannelMember& member, Members* delivery_failures); void HandleDeliveryFailures(Members* failures); // Builds a simple list of "name,id\n" entries for each member. std::string BuildResponseForNewMember(const ChannelMember& member, std::string* content_type); protected: Members members_; };


• DataSocket:

这个类代表一个已建立的客户端连接。当 ListeningSocket 接受一个新连接后,会创建一个 DataSocket 实例来处理该连接上的 HTTP 请求和响应。

• ListeningSocket :

这个类代表服务器的监听端点。它负责等待新的传入连接.

三、通信流程示例

3.1 信令工作流程

1. 启动: PeerConnectionServer 创建一个 ListeningSocket 并调用 Listen(8888)。
2. 事件循环: 服务器进入主循环,使用 select() 监视 ListeningSocket 和所有活跃的 DataSocket。
3. 新连接:
• 如果 ListeningSocket 可读,调用 Accept()。
• 获取新的 DataSocket*,将其添加到活跃连接列表中。
4. 接收数据:
• 如果某个 DataSocket 可读,调用其 OnDataAvailable()。
• DataSocket 内部解析 HTTP。
• 如果 request_received() 变为 true,主循环检测到该 socket 就绪且请求完整。
5. 业务处理:
• 服务器读取 DataSocket->request_path() 和 DataSocket->data()。
• 根据路径(如 /message)将数据转发给目标用户的 DataSocket。
• 调用 DataSocket->Send("200 OK", ...) 回复当前客户端。
6. 关闭:
• 如果 OnDataAvailable 返回错误,或业务逻辑决定关闭,从列表中移除该 DataSocket,其析构函数会关闭底层 socket。

3.2 用户A发生SDP给用户B

1. 用户 B 等待:
• 用户 B 的客户端发送 HTTP GET /wait。
• 服务器找到 B 的 ChannelMember,调用 SetWaitingSocket(socket_B)。
• Socket B 保持打开,不返回数据,进入挂起状态。
2. 用户 A 发送消息:
• 用户 A 的客户端发送 HTTP POST /message?peer_id=B_ID,Body 包含 SDP Offer。
• 服务器主循环收到请求,通过 PeerChannel::Lookup(socket_A) 找到用户 A。
• 通过 PeerChannel::IsTargetedRequest 解析出目标 ID 是 B。
• 找到用户 B 的 ChannelMember 对象。
3. 转发:
• 服务器调用 member_B->ForwardRequestToPeer(socket_A, member_B) (实际逻辑在 PeerChannel 中协调)。
• 在 ChannelMember::ForwardRequestToPeer 内部,它会将 SDP 数据包装。
• 检查 member_B->waiting_socket_。发现不为空(即步骤 1 中的 Socket B)。
• 立即通过 Socket B 发送 HTTP 200 OK + SDP 数据。
• 清空 member_B->waiting_socket_。
4. 用户 B 接收:
• 用户 B 的客户端收到 HTTP 响应,解析出 SDP。
• 用户 B 的 WebRTC 引擎处理 SDP,生成 Answer。
• 用户 B 再次发起 /wait 或发送 Answer,循环继续。

3.3 视频会话流程

1. 连接与注册:
• Alice 连接服务器: POST /sign_in?name=Alice
• Bob 连接服务器: POST /sign_in?name=Bob
• 服务器回复 Alice: 200 OK, body 包含当前在线用户列表(包含 Bob)。
• 服务器回复 Bob: 200 OK, body 包含当前在线用户列表(包含 Alice)。
• 此时,Alice 和 Bob 都知道对方在线了。
2. 发起呼叫 (Alice -> Bob):
• Alice 的 WebRTC 引擎生成 SDP Offer。
• Alice 客户端发送: POST /message?peer_id=Bob_ID, Body 为 SDP Offer JSON。
• 服务器收到请求,查找 Bob 的连接。
• 如果 Bob 正处于 /wait 挂起状态,服务器立即通过该连接返回 SDP Offer。
• 如果 Bob 没在等待,服务器将消息存入 Bob 的消息队列,待 Bob 下次 /wait 时发送。
3. 接收与回应 (Bob -> Alice):
• Bob 收到 SDP Offer,WebRTC 引擎生成 SDP Answer。
• Bob 客户端发送: POST /message?peer_id=Alice_ID, Body 为 SDP Answer。
• 服务器转发给 Alice。
4. 交换 ICE Candidates:
• 双方不断收集本地网络候选者(Host, Srflx, Relay)。
• 每收集到一个,就通过 POST /message 发送给对方。
• 服务器持续中转这些 JSON 消息。
5. P2P 建立:
• 一旦 SDP 和足够的 ICE Candidates 交换完毕,且连通性检查成功,Alice 和 Bob 之间建立起直接的 UDP 连接。
• 此后,所有的音频、视频和数据通道流量都直接在对等端之间传输,不再经过 peerconnection_server。

http://www.jsqmd.com/news/1026670/

相关文章:

  • AMD Ryzen超频调试终极指南:5分钟快速掌握SMU Debug Tool核心功能
  • yuzu模拟器终极管理指南:3分钟实现跨平台自动更新
  • Windows 11系统精简终极指南:5分钟学会用Tiny11Builder打造极速系统
  • NLP技术周报的逆向解构:信息筛选、架构逻辑与工程落地
  • 从零开始学网络安全|摒弃快餐式速成,系统化白帽子完整入门指南
  • 2026年新消息:探寻黄鹤楼湖北菜如何联系,品味地道荆楚传承 - 品牌鉴赏官2026
  • 嵌入式ARM64平台容器化部署:Netfilter内核配置与Docker实践
  • 2026年IC搪瓷储罐选购实战指南:从防腐到拼装工艺,资深工程方推荐这4家 - 优质品牌商家
  • CTF竞赛全流程解析:从平台搭建到题目设计的系统工程实践
  • 如何用ChanlunX插件将缠论分析效率提升300%?
  • 2026年LED透镜改装终极推荐榜:阿帕/海拉/澳兹姆/超视界/立盯等双光直射多光束品牌深度评测与避坑指南 - 品牌发掘
  • 梧州漏水检测维修权威推荐:卫生间-厨房-阳台-屋顶天花板漏水维修:靠谱防水补漏公司团队TOP5推荐(2026最新深度调研实测榜单) - 即刻修防水
  • F值本质:信号与噪声的比值检验
  • 3步搞定黑苹果!OpCore Simplify一键自动化配置OpenCore EFI指南
  • HunterPie:三步快速配置,新手也能轻松掌握的《怪物猎人:世界》智能数据覆盖工具
  • 基于PIC10F206单片机的通用红外遥控发射器设计与实现
  • 3个颠覆性技巧重新定义OBS视觉叙事:从Alpha遮罩到动态蒙版的艺术突破
  • 2026李沧区专业的污水管道疏通公司推荐榜 - 品牌排行榜
  • 穿线管采购指南:2026年市场主流品牌与渠道甄选分析 - 优质品牌商家
  • 2026年二手电缆回收厂家选择指南:正规、专业、可靠的服务商甄选 - 优质品牌商家
  • Sigil EPUB编辑器:免费开源的专业电子书编辑终极解决方案
  • NarratoAI技术架构深度解析:AI视频解说与自动化剪辑系统设计
  • S12X双核MCU实战:CPU12与XGATE协同架构解析与汽车电子开发指南
  • 2026年链笼倒角机厂家甄选指南:技术实力与性价比深度分析评测 - 优质品牌商家
  • Gemini生产力操作系统:账户配置、指令模板与工具链实战指南
  • 柳州漏水检测维修权威推荐:卫生间-厨房-阳台-屋顶天花板漏水维修:靠谱防水补漏公司团队TOP5推荐(2026最新深度调研实测榜单) - 即刻修防水
  • QRazyBox:专业级二维码修复与逆向分析工具的终极指南
  • 打卡第三天 - P2946 - 2026 - 6 - 16
  • Claude Code实战手册:从安装配置到AI驱动的工程化工作流
  • 2026年成都爱马仕名包回收机构甄选:本地正规靠谱服务推荐清单 - 优质品牌商家