WebRTC → 信令服务器

news2024/11/9 2:14:46

相关简介

信令:驱动系统运转。控制各个模块的前后调用关系;业务不同,逻辑不同,信令也会千差万别

要实现一对一通信,驱动系统的核心就是信令。信令控制着系统各个模块之间的前后调用关系,比如当收到用户成功加入房间后,系统需要立即将RTCPeerConnention对象创建好,以便向STUN/TURN服务器请求外网的IP地址和端口;而当收到另一个用户加入房间的消息时,系统需要将自己的外网IP地址和端口交换给对方,从而建立起Socket连接;

WebRTC使用信令服务器交换媒体信息网络候选者信息,信令服务器承担着消息传输和交换的工作,WebRTC规定了信令服务器的实现方式:任何能够进行网络信息交换的技术都可以用来实现信令服务器,如HTTP、XMPP及WebSocket

信令服务器主要作用

  • 实现业务层管理* 如用户创建房间,加入房间,退出房间等* 确定何时初始化、关闭和修改通话会议,也可以进行错误报告
  • 让通信双方彼此交换网络信息* 最常见的是交换通信双方的IP地址和端口 - ICE Candidate* 两个WebRTC之间会尽可能选择P2P进行传输,同一个局域网内直接通过P2P进行传输,不同局域网内需要使用P2P穿越后进行数据传输,P2P穿越成功后直接传输,失败后进行中转等 - 后续的候选人中进行解说
  • 通信双方交换媒体信息* 媒体信息用SDP来表示,这个SDP可以简单理解为:媒体类型的编码器是什么、是否支持该媒体类型和对应的编码器、编码方式是什么等

最简单的信令系统的分类

  • 客户端发送给服务器的信令
  • 服务端发送给客户端的信令

常见的信令系统

  • 客户端* 用户加入房间 - join* 用户离开房间 - leave* 端到端的命令 - message
  • 服务端* 用户已加入 - joined* 用户已离开 - left* 其他用户已加入 - other_joined* 其他用户已离开 - bye* 房间已满 - full
信令传输协议的选择

一般选择TCP或者基于TCP的HTTP/HTTPS、WS/WSS等协议作为信令服务器的传输协议;

  • 原因一:TCP是可靠的传输协议,可以保证传输的数据可靠、有序到达
  • 原因二:TCP上传输数据是流式的,不必担心传输的数据过大导致的拆包传输的问题

信令服务器的常见特点

  • 可以同时支撑多个WebRTC通话环境,即多个房间,且房间之间互不影响
  • 每个房间的参与人数不受限制
  • 实时性好,不可有明显的延时
  • 支持可靠的信令传输,发送者要知道明确的发送反馈,即使发送失败了
  • 性能好、可拓展性要好,要兼顾后续的拓展功能如传输应用数据等

信令时序

在发送信令前,各端需要先与信令服务器SigServer建立连接,建立连接后终端会向信令服务器发送join消息,服务器收到该消息后会返回joined消息(信令服务器在收到该信令后,会先将该用户加入服务器管理的房间,然后向客户端返回joined信令),标识已加入房间,同理其他用户加入也是类似只是会收到otherjoin的消息;> 房间:房间服务器将多端聚集到一起管理;

WebRTC信令如何工作

  • A和B通过WebSocket连接或顺序HTTP请求连接到WebRTC信令服务器;
  • A与WebRTC信令服务器之间的通信称为offer-answer机制,是WebRTC的一部分
  • 对等点A和对等点B之间的连接是为了在设备之间直接发送媒体而建立的。要到达哪里,对等点必须首先通过WebRTC信号服务器进行通信

WebRTC一对一架构

WebRTC 组成部分

分别是两个WebRTC终端、一个信令服务器、一台中继服务器(STUN/TURN)和两个NAT,这是最经济的一对一通信架构。其中信令服务器与中继服务器都在NAT外,也就是属于外网。而两个WebRTC终端在NAT内,属于内网;> 终端知道对方的IP地址后通过NAT穿越进行P2P连接和传输

WebRTC通信步骤

  • 两个终端通信前,都要先与信令服务器连接;
  • 交换信息前,WebRTC终端还要与STUN/TURN服务器建立连接,这样做的目的是通过STUN/TURN服务器获得各自的外网IP地址(子网和公网)、端口和NAT结构(IP地址和端口对我们称之为ICE Candidate)
  • 连接后通信双方就可以通过信令服务器彼此交换信息了,如获取到对方的外网IP地址和端口等信息;
  • 当获得彼此信息后,就可以尝试NAT穿越,进行P2P连接了

WebRTC架构细化

在Call端内部,首先调用音视频设备检测模块检测终端是否有可用的音视频设备,即步骤❶;然后执行第❷步,调用音视频采集模块从设备中采集音视频数据;采集到数据后,执行第❸步开启客户端录制(是否开启录制是可选的,用户可以根据自己的需求选择录制或不录制);当数据采集相关的工作就绪后,执行第❹步,通过信令模块与信令服务器建立连接;紧接着执行第❺步,创建RTCPeerConnection对象(RTCPeerConnection对象是WebRTC最核心的对象,后面音视频数据的传输都靠它来完成)。RTCPeerConnection创建好后,系统要先将它与之前采集的音视频数据绑定到一起,这样RTCPeerConnection才知道从哪里获取要发送的数据。以上就是图4.2中前五步所完成的工作。> 接下来再来看一下RTCPeerConnection创建socket连接的过程。要建立socket连接,RTCPeerConnection首先要执行图4.2中的第❻步,向STUN/TRUN服务器发送请求。STUN/TURN服务器收到Call的请求后,会将Call的外网IP地址和端口号作为应答消息返回去;之后终端执行第❼步,通过信令服务器将Call的连接地址发送给对端。同理,Called也会将它的IP地址和端口发给Call。当通信双方都获得对端的地址后,执行第❽步,此时socket连接就被建立起来了。至此,RTCPeerConnection就可以将音视频数据源源不断地发送给对端。以上就是WebRTC一对一通信的完整过程。

连接双方通过第三方服务器来交换各自的ICE Candidate,如果连接双方在同一个NAT下那么他们仅可以通过内网Candidate就能建立连接,反之就需要STUN Server识别出的公网Candidate进行通信;> 当公网Candidate都无法建立连接时,就说明有一方处于对称NAT下,这就需要处于对称NAT下的客户端去寻找TURN Server提供的转发服务,然后将转发形成的Candidate共享(Signalling)给对方;> 总结:同一个NAT非对称NAT对称NAT服务中转共享Candidate

RTCPeerConnection

RTCPeerConnection对象是WebRTC的核心,同时也是暴露给用户的统一接口,内部包含了网络处理模块服务质量模块音视频引擎模块等,可以将其理解成一个Socket,可以快速稳定的实现端到端的数据传输,创建RTCPeerConnection需要传入STUN/TURN服务器等相关信息

WebRTC信令机制

WebRTC信令使用称为ICE的协议,该协议收集、交换,然后尝试使用ICE候选者连接会话,ICE候选者是可以让对等点相互连接的潜在地址

ICE使得数据包到达目标对等方的三种方法

通过三种方法,ICE可以计算出最快、最简单的NAT穿越路由,以便使数据包到达其目标对等方

  • 方法一:UDP连接* 使用从设备操作系统和网卡获取的IP地址建立UDP连接,这将不可避免地在NAT后面的设备上失败 - 忽略该方法
  • 方法二:STUN服务器* STUN服务器是WebRTC信令中最常用的方法。* STUN服务器检查传入请求的IP地址和端口,然后将该地址发送给对等方作为响应。* 这允许应用程序提供一个可公开访问的地址,然后通过信令机制将其发送给另一个WebRTC对等点
  • 方法三:TURN中继服务器* TURN服务器用于在对等点之间传输音视频和其他实时数据,由于它支持对等方之间的实时数据交换,因此不共享信号信息;* TURN服务器具有公共地址,因此对等方可以连接到他们,即使他们位于NAT和防火墙之后

构建信令服务器

信令服务器的实现方案

原生方案

使用原生C/C++、Java等语言从零开发一个信令服务器,这种方案的实现成本非常高

现成的技术

利用现成的Web服务器做应用开发,如以Apache、Nginx、NodeJS等为服务,在其上做应用开发是不错的选择

优势
  • 一般信令系统都需要使用HTTP/HTTPS、WS/WSS等基于TCP的传输协议,而Apache、Ng inx、NodeJS等服务器显然在这方面有天然的优势
  • 实时通信的信令服务器一般负荷不会很高,这个量级对于Node和Nginx来说,单台服务器就可以了,再者通过Nginx和Node实现起来也相对容易些,且稳定性也挺高

信令服务器的业务逻辑

最重要的就是房间的概念,只有成功创建和加入了房间后才可以进行数据交换,再者当通信的双方结束通话后,用户需要发送离开房间的消息给信令服务器,此时信令服务器需要将房间内的所有人清除,当房间内没有人了时,还需要将房间进行销毁

信令服务器的实现

WebRTC的服务器
  • room应用服务器
  • 信令服务器* WebRTC依靠信令服务器来建立对等点之间的连接,而信令是计算机如何利用WebRTC发现其他计算机来连接的;* 信令服务器本身不直接处理数据流,因为这是在对等点之间完成的,WebRTC信令服务器仅处理有关客户端的元数据或数据* 一旦每个客户端都获得了所有其他连接客户端的SDP提供,他们就开始点对点连接,而无需使用任何服务器* 处理信息如下:* 客户端配置:客户端窗口分辨率、Web APP如何连接到该用户的媒体设备、客户端需要用哪些编解码器进行媒体播放和传输* 网络信息:网络地址和端口等信息* 在WebRTC的每一端,当创建好 RTCPeerConnection 对象,且调用了setLocalDescription 方法后,就开始收集 ICE候选者了* ICE候选者 - 主机候选者:表示的是本地局域网内的IP地址和端口,其优先级是最高的 - 在WebRTC中会首先尝试本地局域网内建立连接* ICE候选者 - 反射候选者:表示的是获取NAT内主机的外网IP地址和端口。优先级第二, - 当本地局域网内连接不通时会尝试通过反射候选者获得的IP地址和端口进行连接;WebRTC内部会探测用户的NAT类型,最终采用不同的方法进行NAT穿越
  • 流媒体中转服务器* 媒体服务器的最大特点是不仅在于它可以向N人发送广播,而且媒体服务器处理转码和编码,甚至将WebRTC流重新打包到其他协议,进行缩放,甚至添加自适应流功能让观众开心,媒体服务器也可以充当WebRTC信令服务器,如Ant Media Server
  • NAP穿越服务器* socket.io本身就有房间的概念,也具有信令转发的功能,因此可以用socket.io代替WebRTC中的room服务器和信令服务器
存在的问题及解决办法
  • 如何创建一个HTTP服务* 通过Node的HTTP/HTTPS库和express库进行实现
  • 如何使用socket.io库* 在Node中通过requier进行引入,然后利用socket.io的API进行交互实现如on方法接收消息,emit发送消息,具体API参考官网socket.io浅析
  • 如何进行信令转发* 需要根据收到的不同的信令,返回不同的结果
io.sockets.on("connection", (socket) => {//收到message时,直接进行转发socket.on("message", (message) => {//给另一端转发消息socket.to(room).emit("message", message);});//收到 join 消息socket.on("join", (room) => {// 首先将用户加入服务端管理的房间中,之后向客户端返回joined消息var o = io.sockets.adapter.rooms[room];//得到房间里的人数var nc = o ? Object.keys(o.sockets).length : 0;if (nc < 2) {//如 果 房 间中 没 有 超 过 2 人socket.join(room);//发 送 joined消 息socket.emit("joined", room);//...} else {// max two clientssocket.emit("full", room); //发 送 full 消 息}});//...}); ``````
"use strict " 
var log4js = require("log4js "); // 用于输出日志
var http = require("http"); // 提供HTTP 服务
var https = require("https "); // 提供HTTPS 服务
var fs = require("fs"); // 用于读取文件内容
var socketIo = require("socket.io");
var express = require("express ");
var serveIndex = require("serve -index ");
// 一个房间里可以同时在线的最大用户数
var USERCOUNT = 3;
// 日志的配置项
log4js.configure({appenders: {file: {type: "file",filename: "app.log",layout: {type: "pattern ",pattern: "%r %p - %m",},},},categories: {default: {appenders: ["file"],level: "debug ",},},
});
var logger = log4js.getLogger();
var app = express();
app.use(serveIndex("./ public "));
app.use(express.static("./ public "));
// 设置跨域访问
app.all("*", function (req, res, next) {// 设置允许跨域的域名, * 代表允许任意域名跨域res.header("Access -Control -Allow -Origin", "*");// 允许的header 类型res.header("Access -Control -Allow -Headers", "content -type");// 跨域允许的请求方式res.header("Access -Control -Allow -Methods","DELETE ,PUT ,POST ,GET ,OPTIONS");if (req.method.toLowerCase() == "options ") {res.send(200); // 让options 尝试请求快速结束} else {next();}
});
//HTTP 服务
var http_server = http.createServer(app);
http_server.listen(80, "0.0.0.0 ");
// 你的网站证书
var options = {key: fs.readFileSync("./cert/cert.key"),cert: fs.readFileSync("./cert/cert.pem"),
};
// HTTPS 服务
var https_server = https.createServer(options, app);
var io = socketIo.listen(https_server);
// 处理连接事件
io.sockets.on("connection ", (socket) => {// 中转消息socket.on("message ", (room, data) => {logger.debug("message , room: " + room + ", data , type:" + data.type);socket.to(room).emit("message ", room, data);});// 用户加入房间socket.on("join", (room) => {socket.join(room);var myRoom = io.sockets.adapter.rooms[room];var users = myRoom ? Object.keys(myRoom.sockets).length : 0;logger.debug("the user number of room (" + room + ") is: " + users);// 如果房间里人未满if (users < USERCOUNT) {// 发给除自己之外的房间内的所有人socket.emit("joined ", room, socket.id);// 通知另一个用户, 有人来了if (users > 1) {socket.to(room).emit("otherjoin ", room, socket.id);}} else {// 如果房间里人满了socket.leave(room);socket.emit("full", room, socket.id);}});// 用户离开房间socket.on("leave ", (room) => {// 从管理列表中将用户删除socket.leave(room);var myRoom = io.sockets.adapter.rooms[room];var users = myRoom ? Object.keys(myRoom.sockets).length : 0;logger.debug("the user number of room is: " + users);// 通知其他用户有人离开了socket.to(room).emit("bye", room, socket.id);// 通知用户服务器已处理socket.emit("leaved ", room, socket.id);});
});

https_server.listen(443, "0.0.0.0 "); 

最后

最近找到一个VUE的文档,它将VUE的各个知识点进行了总结,整理成了《Vue 开发必须知道的36个技巧》。内容比较详实,对各个知识点的讲解也十分到位。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/185380.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

3D模型在线查看利器【多种格式】

BimAnt 3DViewer网站可以 打开多种 3D 文件格式并在你的浏览器中可视化展示3D模型&#xff0c;支持 obj、3ds、stl、ply、gltf、glb、off、 3dm、fbx 等等。 1、支持的3D模型格式 BimAnt 3DViewer网站支持多种文件格式的导入和导出。 如果文件格式有文本和二进制版本&#x…

Minecraft 1.19.2 Fabric模组开发 09.Mixin

我们今天用mixin在1.19.2 fabric中实现一个望远镜 1.由于fabric已经自动配置好了mixin&#xff0c;所以我们无需配置mixin&#xff0c;先在ItemInit中新建一个我们的望远镜物品&#xff1a; ItemInit.java public static final Item BIRDWATCHER registerItem("birdwat…

Smart-doc的脚本生成在线文档(精简官方文档描述)

Smart-doc优点&#xff1a; 无侵入的接口文档、在线文档生成器。三种生成文档方式。对于程序代码开发中只需要加注释&#xff08;符合一定的语法&#xff0c;五分钟可掌握&#xff09;就能生成在线文档。可以支持c、java、php、node等等常见的主流语言。 如何使用&#xff1a; …

47.Isaac教程--ORB

ORB ISAAC教程合集地址: https://blog.csdn.net/kunhe0512/category_12163211.html 文章目录ORBGem 提供的类型关键点描述符如何使用 Gem&#xff08;界面&#xff09;构建包Isaac Codelets示例应用程序主机设备嵌入式 Jetson 设备这个 gem 提供了一个特征检测器和描述符提取器…

2011年专业408算法题

文章目录0 结果1 题目2 思路2.1 思路1&#xff08;暴力解&#xff1a;排序&#xff09;2.2 思路2&#xff08;较优解&#xff1a;归并合并数组&#xff09;2.3 思路3&#xff08;较优解&#xff1a;数组指针后移&#xff09;2.4 思路4&#xff08;最优解&#xff1a;两个数组的…

webpack是如何进行依赖图谱收集的?

我自己学习webpack已有很长时间了&#xff0c;但是经常会遇到这样的问题: 可以熟练配置webpack的一些常用配置&#xff0c;但是对一些不常见的api或者概念总是云里雾里。因此&#xff0c;对着网上资料手写了一个简易版的webpack&#xff0c;现在对其中的依赖图谱收集部分进行梳…

Numpy(7)—字节交换、NumPy 副本和视图、深浅拷贝、矩阵库、NumPy 线性代数、NumPy IO(读写)、NumPy Matplotlib

1.字节交换 import numpy as npA np.array([1, 256, 8755], dtypenp.int16) print(A) print(list(map(hex, A))) print(A.byteswap(inplaceTrue)) print(list(map(hex, A)))2.NumPy 副本和视图 副本是一个数据的完整的拷贝&#xff0c;如果我们对副本进行修改&#xff0c;它不…

【MyBatis 持久层框架】Mapper代理开发详细解读

文章目录1. 前言2. Mapper 代理开发3. 过程剖析4. 总结1. 前言 前面在 MyBatis 快速入门篇中&#xff0c;我们使用了 MyBatis 原生的开发方式操作数据库&#xff0c;解决了 JDBC 操作数据库时的硬编码和操作繁琐的问题。实际上&#xff0c;在 Java 项目中&#xff0c;我们更常…

python3——函数

目录 一、函数定义 二、函数调用 1.打印Hello World 2.判断最大值 3.计算矩形面积 4.help说明文档 三、参数传递 (一)位置参数 (二)关键字参数 (三)默认参数(缺省参数) (四)可变参数(收集参数) 1.位置可变参数(接收所有的位置参数&#xff0c;返回一个元组) 2.关键…

高通开发系列 - MSM8909 lk aboot阶段点灯操作

By: fulinux E-mail: fulinux@sina.com Blog: https://blog.csdn.net/fulinus 喜欢的盆友欢迎点赞和订阅! 你的喜欢就是我写作的动力! 目录 第一种LK提供的接口实现第二种直接操作寄存器这篇文章之前请参考下:高通开发系列 - MSM8909指示灯操作 在LK中点灯有两种方式,一种…

JAVA-定位排查bug

在开发过程中难免会遇到bug&#xff0c;理解bug的含义&#xff0c;定位bug的位置&#xff0c;对于解决bug至关重要&#xff01;掌握高效的排错技巧&#xff0c;对于程序员来说必不可少。 目录 一、错误异常的分类 二、常见报错信息及原因&#xff08;持续更新中&#xff09;…

域内权限维持:AdminSDHolder

01、简介 AdminSDHolder是一个特殊的AD容器&#xff0c;通常作为某些特权组成员的对象的安全模板。Active Directory将采用AdminSDHolder对象的ACL并定期将其应用于所有受保护的AD账户和组&#xff0c;以防止意外和无意的修改并确保对这些对象的访问是安全的。如果攻击者能完全…

Flex布局和主要属性用法详解

目录 前言 一个小例子 基本概念&#xff1a; 设置在主轴上的排列方式 设置在侧轴上的排列方式 更换主轴和侧轴方向 换行 align-content属性 元素&#xff08;子容器&#xff09;的相关属性 flex-basis flex-grow flex-shrink属性 flex属性 前言 flex布局是继标准…

JDBC-Statement

1.Statement执行静态sql语句&#xff08;“字符串”&#xff09; 返回结果 2.&#xff01;实际工作一般用PreparedStatement来进行sql语句的执行&#xff0c;因为sql注入的风险 3and4.SQl注入就是Statement没有检查我们输入sql语句&#xff0c;一些别有用心的可能写一些危害数据…

智能手表主控芯片盘点,智能手表GUI,智能手表市场

聚焦&#xff1a;无线连接芯片&#xff0c;市场&#xff0c;技术 祝大家新年快乐&#xff0c;开工大吉&#xff01;趁寒假简单梳理了下智能手表应用&#xff0c;做个分享&#xff0c;不对的地方欢迎交流指正&#xff1b; 01 市场容量&#xff0c;分类及拓扑 2个数据供参考 一个…

C++ dll、lib 的定义以及引用,

最近在研究socket&#xff0c;发现socket程序要依赖ws2_32.dll,涉及到动态链接库&#xff0c;有点懵&#xff0c;上网恶补了一下链接库的知识&#xff0c;最后总结出这么一篇文章 链接库分为两种&#xff1a;动态链接库(dll) 和静态链接库(lib) 动态链接库 &#xff1a; 动态链…

【C++】C++11语法解析

&#x1f308;欢迎来到C专栏~~C11 (꒪ꇴ꒪(꒪ꇴ꒪ )&#x1f423;,我是Scort目前状态&#xff1a;大三非科班啃C中&#x1f30d;博客主页&#xff1a;张小姐的猫~江湖背景快上车&#x1f698;&#xff0c;握好方向盘跟我有一起打天下嘞&#xff01;送给自己的一句鸡汤&#x1f…

大数据分析案例-基于多元线性回归算法构建用户信用评分模型

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

ue4c++日记9(指定区域生成角色)

目录 创建C类 头文件 代码文件 结果 创建C类 头文件 // Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "ASPawnVolum.generated…

vSphere with Tanzu概念介绍

vSphere with Tanzu是在vSphere7.0及之后出现的新功能&#xff0c;它可以在虚拟化层创建一个Kubernetes 控制平面&#xff0c;并将vSphere 集群资源转化为Kubernetes集群资源&#xff0c;这样可以直接在ESXI主机上运行Kubernetes工作负载&#xff0c;创建Kubernetes集群并部署容…