WebRTC的ICE之TURN协议的交互流程中继转发Relay媒体数据的turnserver的测试

WebRTC的ICE之TURN协议的交互流程和中继转发Relay媒体数据的turnserver的测试

WebRTC的ICE之TURN协议的交互流程中继转发Relay媒体数据的turnserver的测试

  • WebRTC的ICE之TURN协议的交互流程和中继转发Relay媒体数据的turnserver的测试
  • 前言
  • 一、TURN协议
    • 1、连接Turn Server 流程
      • ① 抓包交换流程图
      • ② TURN协议格式解析
        • 协议基础与消息结构
        • 关键方法类型
        • 核心属性类型
        • 错误码与状态‌
        • 数据传输机制‌
      • ③ 发送Allocate Request UDP 信息包信息
        • 再次发送 Allocate Request UDP 包 带上 协议、用户名和sha-1(user:realm:paasword)签名
      • ④ 发送CreatePermission Request
      • 发送数据Send Indication
      • 接收 Data Indiaction
      • ⑤ Channel-Bind Request
        • 发送数据 ChannelData Message
    • 2、 TURN测试Demo
    • 二 、 iceCandidate收集的时机有两种
      • 1、创建PeerConnection对象传入的参数ice_candidate_pool_size大于0会创建连接池的个数, 如果没有不会创建连接池ICE的速度就会有点慢
      • 2、 设置sdp时获取 iceCandidate
  • 总结


前言

TURN协议:文档RFC5766

文档中TURN协议工作原理图

                                     Peer AServer-Reflexive    +---------+Transport Address   |         |192.0.2.150:32102   |         ||              /|         |TURN              |            / ^|  Peer A |Client's              Server            |           /  ||         |Host Transport        Transport         |         //   ||         |Address               Address           |       //     |+---------+10.1.1.2:49721       192.0.2.15:3478     |+-+  //     Peer A|               |               ||N| /       Host Transport|   +-+         |               ||A|/        Address|   | |         |               v|T|     192.168.100.2:49582|   | |         |               /+-++---------+|   | |         |+---------+   /              +---------+|         ||   |N|         ||         | //               |         || TURN    |v   | |         v| TURN    |/                 |         || Client  |----|A|----------| Server  |------------------|  Peer B ||         |    | |^         |         |^                ^|         ||         |    |T||         |         ||                ||         |+---------+    | ||         +---------+|                |+---------+| ||                    |                || ||                    |                |+-+|                    |                ||                    |                ||                    |                |Client's                   |            Peer BServer-Reflexive    Relayed             TransportTransport Address   Transport Address   Address192.0.2.1:7000      192.0.2.15:50000     192.0.2.210:49191

WebRTC中走中继Relay 调用流程图

在这里插入图片描述

一、TURN协议

TURN                                 TURN           Peer          Peerclient                               server          A             B|-- Allocate request --------------->|             |             ||                                    |             |             ||<--------------- Allocate failure --|             |             ||                 (401 Unauthorized) |             |             ||                                    |             |             ||-- Allocate request --------------->|             |             ||                                    |             |             ||<---------- Allocate success resp --|             |             ||            (192.0.2.15:50000)      |             |             |//                                   //            //            //|                                    |             |             ||-- Refresh request ---------------->|             |             ||                                    |             |             ||<----------- Refresh success resp --|             |             ||                                    |             |             |
TURN                                 TURN           Peer          Peerclient                               server          A             B|                                    |             |             ||-- CreatePermission req (Peer A) -->|             |             ||<-- CreatePermission success resp --|             |             ||                                    |             |             ||--- Send ind (Peer A)-------------->|             |             ||                                    |=== data ===>|             ||                                    |             |             ||                                    |<== data ====|             ||<-------------- Data ind (Peer A) --|             |             ||                                    |             |             ||                                    |             |             ||--- Send ind (Peer B)-------------->|             |             ||                                    | dropped     |             ||                                    |             |             ||                                    |<== data ==================||                            dropped |             |             ||                                    |             |             |
--------------------------------------------------------------------------------------

TURN                                 TURN           Peer          Peerclient                               server          A             B|                                    |             |             ||-- ChannelBind req ---------------->|             |             || (Peer A to 0x4001)                 |             |             ||                                    |             |             ||<---------- ChannelBind succ resp --|             |             ||                                    |             |             ||-- [0x4001] data ------------------>|             |             ||                                    |=== data ===>|             ||                                    |             |             ||                                    |<== data ====|             ||<------------------ [0x4001] data --|             |             ||                                    |             |             ||--- Send ind (Peer A)-------------->|             |             ||                                    |=== data ===>|             ||                                    |             |             ||                                    |<== data ====|             ||<------------------ [0x4001] data --|             |             ||                                    |             |             |Figure 4

1、连接Turn Server 流程

和国标gb28181的协议差不多 都是先发送一包AllocateRequest到服务返回一个错误码然后在发送一个AllocateRequest请求带上 用户名和密码 然后Trunserver返回映射turn上ip地址和port端口

在这里插入图片描述

① 抓包交换流程图

在这里插入图片描述

② TURN协议格式解析

协议基础与消息结构

TURN协议基于STUN协议扩展,采用STUN消息格式(头部+属性列表),同时新增了专用于中继功能的方法和属性‌

  1. 消息头(Header):
  • Class‌:固定为0x00(请求)或0x10(指示消息)‌

  • Method‌:定义操作类型(如Allocate、ChannelBind等)‌

  • Length‌:消息总长度(不含头部)‌

  • Transaction ID‌:16字节唯一标识符,用于匹配请求与响应‌

‌2. 属性列表(Attribute)‌:

  • 每个属性由Type(2字节)、Length(2字节)和Value(可变长)组成‌

  • 例如:XOR-RELAYED-ADDRESS表示中继地址,CHANNEL-NUMBER标识信道号‌

关键方法类型

TURN协议新增以下STUN方法

  • Allocate‌:客户端向服务器申请中继地址,响应中包含XOR-RELAYED-ADDRESS属性‌
  • Refresh‌:延长中继地址的生命周期(通过LIFETIME属性设置超时时间)‌
  • ChannelBind‌:绑定信道号(CHANNEL-NUMBER)与特定Peer地址,启用ChannelData传输‌
  • Send/Data Indication‌:用于中继数据传输(Send为客户端→服务器,Data为服务器→客户端
核心属性类型

新增属性包括:

  • XOR-RELAYED-ADDRESS‌:服务器分配的中继地址(IP+端口),用于标识客户端的中继端点‌
  • XOR-MAPPRE-ADDRES: 本机映射外网地址(IP+port)
  • CHANNEL-NUMBER‌:2字节信道号(范围0x4000-0x7FFF),用于ChannelData报文的高效传输‌
  • LIFETIME‌:中继地址有效期(默认10分钟),客户端需定期刷新‌
  • DONT-FRAGMENT‌:标志位,指示客户端支持IP分片重组‌
错误码与状态‌

TURN协议扩展了STUN错误码:

  • 401(未认证)‌:请求未携带有效凭证,需重新发送认证信息‌78‌
  • 437(Allocation Mismatch)‌:客户端尝试使用未分配的信道或地址‌
  • 508(Insufficient Capacity)‌:服务器资源不足,无法分配中继地址‌
数据传输机制‌

1‌. Send/Data Indication‌:

  • 使用STUN消息格式,Send携带应用数据发送至服务器,Data由服务器转发至Peer‌
  • 头部包含XOR-PEER-ADDRESS属性,标识目标Peer地址‌67。
  1. ChannelData消息‌:
  • 非STUN格式,头部仅4字节(信道号+数据长度),减少传输开销‌
  • 需通过ChannelBind预先绑定信道号与Peer地址‌

③ 发送Allocate Request UDP 信息包信息

在这里插入图片描述

第一次返回 401 Unauthorized 信息 带有NONE(新生成的一次性随机数),REALM(标识服务器或服务的域)
在这里插入图片描述

再次发送 Allocate Request UDP 包 带上 协议、用户名和sha-1(user:realm:paasword)签名

密码

TURN服务返回 本机映射外网地址和TURN服务分配中继地址、有效时间
在这里插入图片描述

④ 发送CreatePermission Request

在这里插入图片描述
返回数据
在这里插入图片描述

发送数据Send Indication

!【】
在这里插入图片描述

接收 Data Indiaction

在这里插入图片描述

⑤ Channel-Bind Request

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgithub.com%2Fchensongpoixs%2Fcturn_relay_demo&pos_id=img-B8Tiv02W-1743192961278)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fchensongpoixs.github.io%2F&pos_id=img-om16XyoI-1743192922198)
在这里插入图片描述

发送数据 ChannelData Message

在这里插入图片描述

2、 TURN测试Demo

TURN测试demo
在这里插入图片描述

二 、 iceCandidate收集的时机有两种

1、创建PeerConnection对象传入的参数ice_candidate_pool_size大于0会创建连接池的个数, 如果没有不会创建连接池ICE的速度就会有点慢

设置ice配置


bool Conductor::CreatePeerConnection(bool dtls) {RTC_DCHECK(peer_connection_factory_);RTC_DCHECK(!peer_connection_);RTC_LOG(LS_INFO) << __FUNCTION__;webrtc::PeerConnectionInterface::RTCConfiguration config;config.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan; //这个 config.enable_dtls_srtp = dtls; //是否加密webrtc::PeerConnectionInterface::IceServer server;server.uri = GetPeerConnectionString();config.ice_candidate_pool_size = 0; // 大于0 就在sdp之前进行stun和turn连接创建, 反之啥事情都不做server.username = user_name_;server.password = pass_word_;std::vector<std::string> turnservers;turnservers.push_back(turn_url_);server.urls = turnservers;// 设置走 turn server 进行转发媒体数据 哈config.type = webrtc::PeerConnectionInterface::kRelay;config.servers.push_back(server);peer_connection_ = peer_connection_factory_->CreatePeerConnection(config, nullptr, nullptr, this);return peer_connection_ != nullptr;
}

在CreatePeerConnection方法中

  1. 异步创建BasicPortAllocator对象中如果ice_candidate_pool_size大于在SetConfiguration方法中就会进行连接turn和stun服务
  2. 创建负责ICE管理类JsepTransportController
bool PortAllocator::SetConfiguration(const ServerAddresses& stun_servers,const std::vector<RelayServerConfig>& turn_servers,int candidate_pool_size,bool prune_turn_ports,webrtc::TurnCustomizer* turn_customizer,const absl::optional<int>& stun_candidate_keepalive_interval) 
{CheckRunOnValidThreadIfInitialized();// A positive candidate pool size would lead to the creation of a pooled// allocator session and starting getting ports, which we should only do on// the network thread.RTC_DCHECK(candidate_pool_size == 0 || thread_checker_.IsCurrent());bool ice_servers_changed = (stun_servers != stun_servers_ || turn_servers != turn_servers_);stun_servers_ = stun_servers;turn_servers_ = turn_servers;prune_turn_ports_ = prune_turn_ports;if (candidate_pool_frozen_) {if (candidate_pool_size != candidate_pool_size_) {RTC_LOG(LS_ERROR) << "Trying to change candidate pool size after pool was frozen.";return false;}return true;}if (candidate_pool_size < 0) {RTC_LOG(LS_ERROR) << "Can't set negative pool size.";return false;}candidate_pool_size_ = candidate_pool_size;// If ICE servers changed, throw away any existing pooled sessions and create// new ones.///// 20250328 ice[stun、turn]信息改变 就清除当前端口连接池会话if (ice_servers_changed) {pooled_sessions_.clear();}turn_customizer_ = turn_customizer;// If |candidate_pool_size_| is less than the number of pooled sessions, get// rid of the extras.while (candidate_pool_size_ < static_cast<int>(pooled_sessions_.size())) {pooled_sessions_.back().reset(nullptr);pooled_sessions_.pop_back();}///// |stun_candidate_keepalive_interval_| will be used in STUN port allocation// in future sessions. We also update the ready ports in the pooled sessions.// Ports in sessions that are taken and owned by P2PTransportChannel will be// updated there via IceConfig.// ICE的心跳包  的stun_candidate_keepalive_interval_ = stun_candidate_keepalive_interval;for (const auto& session : pooled_sessions_) {session->SetStunKeepaliveIntervalForReadyPorts(stun_candidate_keepalive_interval_);}// If |candidate_pool_size_| is greater than the number of pooled sessions,// create new sessions.while (static_cast<int>(pooled_sessions_.size()) < candidate_pool_size_) {IceParameters iceCredentials = IceCredentialsIterator::CreateRandomIceCredentials();PortAllocatorSession* pooled_session = CreateSessionInternal("", 0, iceCredentials.ufrag, iceCredentials.pwd);pooled_session->set_pooled(true);//20250327  触发MSG_CONFIG_START信号   探测stun和turn 服务连通性 pooled_session->StartGettingPorts();pooled_sessions_.push_back(std::unique_ptr<PortAllocatorSession>(pooled_session));}return true;
}

2、 设置sdp时获取 iceCandidate

整体调用流程

在这里插入图片描述

调用流程图
在这里插入图片描述


bool TurnPort::HandleIncomingPacket(rtc::AsyncPacketSocket* socket,const char* data,size_t size,const rtc::SocketAddress& remote_addr,int64_t packet_time_us) {if (socket != socket_) {// The packet was received on a shared socket after we've allocated a new// socket for this TURN port.return false;}// This is to guard against a STUN response from previous server after// alternative server redirection. TODO(guoweis): add a unit test for this// race condition.if (remote_addr != server_address_.address) {RTC_LOG(LS_WARNING) << ToString()<< ": Discarding TURN message from unknown address: "<< remote_addr.ToString() << " server_address_: "<< server_address_.address.ToString();return false;}// The message must be at least the size of a channel header.if (size < TURN_CHANNEL_HEADER_SIZE) {RTC_LOG(LS_WARNING) << ToString()<< ": Received TURN message that was too short";return false;}if (state_ == STATE_DISCONNECTED) {RTC_LOG(LS_WARNING)<< ToString()<< ": Received TURN message while the TURN port is disconnected";return false;}// Check the message type, to see if is a Channel Data message.// The message will either be channel data, a TURN data indication, or// a response to a previous request.uint16_t msg_type = rtc::GetBE16(data);if (IsTurnChannelData(msg_type)) {HandleChannelData(msg_type, data, size, packet_time_us);return true;}if (msg_type == TURN_DATA_INDICATION) {HandleDataIndication(data, size, packet_time_us);return true;}if (SharedSocket() && (msg_type == STUN_BINDING_RESPONSE ||msg_type == STUN_BINDING_ERROR_RESPONSE)) {RTC_LOG(LS_VERBOSE)<< ToString()<< ": Ignoring STUN binding response message on shared socket.";return false;}// This must be a response for one of our requests.// Check success responses, but not errors, for MESSAGE-INTEGRITY.
#if TURN_LOGstd::cout << "[turn][hash()  = " << hash() << "]" << std::endl;RTC_LOG(LS_INFO) << "[turn][hash()  = " << hash() << "]";
#endif // #if TURN_LOGif (IsStunSuccessResponseType(msg_type) &&!StunMessage::ValidateMessageIntegrity(data, size, hash())) {RTC_LOG(LS_WARNING) << ToString()<< ": Received TURN message with invalid ""message integrity, msg_type: "<< msg_type;return true;}request_manager_.CheckResponse(data, size);return true;
}

总结

WebRTC源码分析地址:https://github.com/chensongpoixs/cwebrtc

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

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

相关文章

Redis + Caffeine多级缓存电商场景深度解析

Redis Caffeine多级缓存 Redis Caffeine多级缓存电商场景深度解析一、实施目的二、具体实施2.1 架构设计2.2 组件配置2.3 核心代码实现 三、实施效果3.1 性能指标对比3.2 业务指标改善3.3 系统稳定性 四、关键策略4.1 缓存预热4.2 一致性保障4.3 监控配置Prometheus监控指标 …

前端开发3D-基于three.js

基于 three.js 渲染任何画面&#xff0c;都要基于这 3 个要素来实现 1场景scene&#xff1a;放置物体的容器 2摄像机&#xff1a;类似人眼&#xff0c;可调整位置&#xff0c;角度等信息&#xff0c;展示不同画面 3渲染器&#xff1a;接收场景和摄像机对象&#xff0c;计算在浏…

代码随想录算法训练营--打卡day4

一.移除链表元素 1.题目链接 203. 移除链表元素 - 力扣&#xff08;LeetCode&#xff09; 2.思路 通过 while 循环来遍历链表&#xff0c;只要 cur 的下一个节点不为空&#xff0c;就继续循环。在循环中&#xff0c;对 cur 的下一个节点的值进行判断&#xff1a; 值不等于…

虚拟电厂:多元能源聚合,开启绿色电力新时代

虚拟电厂&#xff1a;多元能源聚合&#xff0c;开启绿色电力新时代 在“双碳”目标驱动下&#xff0c;电力系统正经历从集中式向分布式、从单一能源向多能互补的深刻变革。 作为能源互联网的核心载体&#xff0c;虚拟电厂通过数字化技术整合多种能源资源&#xff0c;而是像指…

高通Android10 铃声通话音频80%音量修改

先修改最高的音量step --- a/SC60_AP/frameworks/base/services/core/java/com/android/server/audio/AudioService.javab/SC60_AP/frameworks/base/services/core/java/com/android/server/audio/AudioService.java-311,14 311,14 public class AudioService extends IAudio…

类加载过程?类隔离了解过吗?

类加载过程详解 类加载是 JVM 将类的字节码从磁盘、网络或其他来源加载到内存&#xff0c;并转换为 Class 对象的过程&#xff0c;主要分为以下 五个阶段&#xff1a; 1. 加载&#xff08;Loading&#xff09; 任务&#xff1a;查找类的二进制字节流&#xff08;如 .class 文…

使用msmtp和mutt在CentOS上发送指定目录下的所有文件作为邮件附件

1.安装 msmtp&#xff1a; 如果尚未安装&#xff0c;请先通过以下命令安装msmtp。 sudo yum install msmtp 2.配置 msmtp 使用新浪邮箱&#xff1a; 创建或编辑配置文件~/.msmtprc&#xff0c;输入以下内容&#xff08;记得替换授权码&#xff09;。 defaults tls on tls_st…

Vue+Elementui首页看板

源码 <template><!-- 查询条件--><div class="optimize-norm" v-loading="selectDataLoading"><el-form :model="queryParams" ref="queryRef" style="padding-bottom:8px" :inline="true"…

汇编学习之《指针寄存器大小端学习》

什么是指针寄存器&#xff1f; 操作栈的寄存器 栈&#xff1a; 保存函数里面传递的参数&#xff0c;局部变量等。 EBP&#xff1a; 指向栈底的指针 ESP&#xff1a; 指向栈顶的指针。 计算入栈地址变化规则 通过OllDbg查看 有可能点击安装的时候栈区域第一次查看会没有显…

Oracle数据库数据编程SQL<3.7 PL/SQL 触发器(Trigger)>

触发器是Oracle数据库中的一种特殊存储过程&#xff0c;它会在特定数据库事件发生时自动执行。触发器通常用于实现复杂的业务规则、数据验证、审计跟踪等功能。 目录 一、触发器基本概念 1. 触发器特点 2. 触发器组成要素 二、触发器类型 1. DML触发器 2. DDL触发器 3.…

2025年渗透测试面试题总结-某 携程旅游-基础安全工程师(题目+回答)

网络安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 携程旅游-基础安全工程师 反序列化原理 核心原理 扩展分析 SQL注入本质 核心原理 扩展分析 SQL注…

CSS 边框(Border)样式详解

CSS 边框&#xff08;Border&#xff09;样式详解 CSS 提供了多种边框样式&#xff0c;使我们能够控制元素的外观。本文将详细介绍 CSS 边框的各种属性及应用示例。 1. 基本边框属性 CSS 主要使用 border 相关属性定义边框&#xff0c;基本语法如下&#xff1a; border: [边…

SpringCould微服务架构之Docker(6)

容器的基本命令&#xff1a; 1. docker exec &#xff1a;进入容器执行命令 2. docker logs: -f 持续查看容器的运行日志 3. docker ps&#xff1a;查看所有运行的容器和状态 案例&#xff1a;创建运行一个容Nginx容器 docker run--name myNginx -p 80:80 -d nginx 命…

unity3d端监听 uri scheme

一、消息监听 1.创建一个脚本命名为 “URISchemeListener” &#xff0c;用于接收URI消息&#xff08;代码如下&#xff09;。 using System; using System.Runtime.InteropServices; using UnityEngine; using UnityEngine.UI;public class URISchemeListener : MonoBehavio…

网络信息安全应急演练方案

信息安全应急演练方案 总则 &#xff08;一&#xff09;编制目的 旨在建立并完善应对病毒入侵、Webshell 攻击以及未授权访问等信息安全突发事件的应急机制&#xff0c;提升组织对这类事件的快速响应、协同处理和恢复能力&#xff0c;最大程度降低事件对业务运营、数据安全和…

电商场景下高稳定性数据接口的选型与实践

在电商系统开发中&#xff0c;API接口需要应对高并发请求、动态数据更新和复杂业务场景。我将重点解析电商场景对数据接口的特殊需求及选型方案。 一、电商API必备的四大核心能力 千万级商品数据实时同步 支持SKU基础信息/价格/库存多维度更新每日增量数据抓取与历史版本对比…

Android R adb remount 调用流程

目的&#xff1a;调查adb remount 与adb shell进去后执行remount的差异 调试方法&#xff1a;添加log编译adbd,替换system\apex\com.android.adbd\bin\adbd 一、调查adb remount实现 关键代码&#xff1a;system\core\adb\daemon\services.cpp unique_fd daemon_service_to…

多模态大语言模型arxiv论文略读(二)

Identifying the Correlation Between Language Distance and Cross-Lingual Transfer in a Multilingual Representation Space ➡️ 论文标题&#xff1a;Identifying the Correlation Between Language Distance and Cross-Lingual Transfer in a Multilingual Representat…

【运维】负载均衡

老规矩&#xff0c;先占坑&#xff0c;后续更新。 开头先理解一下所谓的“均衡”&#xff0c;不能狭义地理解为分配给所有实际服务器一样多的工作量&#xff0c;因为多台服务器的承载能力各不相同&#xff0c;这可能体现在硬件配置、网络带宽的差异&#xff0c;也可能因为某台…

大型语言模型Claude的“思维模式”最近被公开解剖

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…