作者:李俊才 (jcLee95):https://blog.csdn.net/qq_28550263
邮箱 :291148484@163.com
本文地址:https://blog.csdn.net/qq_28550263/article/details/131302130
【介绍】:本系列笔记总结WebRTC用到的相关技术理论及其实践。
目 录
- 第二章:WebRTC 网络协议
- 1. 绘画 会话描述协议(SDP)
- 2. 交互式连接建立(ICE)
- 3. STUN (Session Traversal Utilities for NAT)
- 3.1 STUN 协议简介
- 3.2 STUN 的工作流程
- 3.3 STUN JavaScript 编程
- 3.4 RTCPeerConnection API 解析
- 3.4.1 概述
- 3.4.2 属性
- 3.4.3 方法
- 方法总览
- addIceCandidate():向连接添加一个新的 ICE 候选
- addTrack():向连接添加一个媒体轨道
- addTransceiver():向连接添加一个新的 RTP 发送器/接收器对
- close():关闭连接
- createDataChannel():创建一个新的数据通道
- createOffer():创建一个 SDP 提议
- getConfiguration():获取连接的当前配置
- getReceivers():获取连接的所有 RTCRtpReceiver 对象
- getSenders():获取连接的所有 RTCRtpSender 对象
- getStats():获取连接的统计信息
- getTransceivers():获取连接的所有 RTCRtpTransceiver 对象
- removeTrack():从连接中移除一个媒体轨道
- restartIce():重新启动 ICE 过程
- setConfiguration():设置连接的配置
- setLocalDescription():设置本地 SDP 描述
- setRemoteDescription():设置远程 SDP 描述
- 3.4.4 事件处理程序
- 4. TURN (Traversal Using Relays around NAT)
- 附. 积极拥抱 IPv6 的倡议
第二章:WebRTC 网络协议
1. 绘画 会话描述协议(SDP)
1.1 SDP 协议简介
SDP(Session Description Protocol)是一种用于 描述和协商多媒体会话参数 的文本格式。它由一系列属性(attribute)组成,每个属性由一个 键值对 表示。属性之间用 换行符(CRLF)分隔。比如:
v=0
o=- 2890844526 2890842807 IN IP4 192.0.2.3
s=-
t=0 0
a=group:BUNDLE audio video
m=audio 49170 RTP/AVP 0
c=IN IP4 192.0.2.3
a=rtpmap:0 PCMU/8000
a=ptime:20
m=video 51372 RTP/AVP 99
c=IN IP4 192.0.2.3
a=rtpmap:99 VP8/90000
a=rtcp-fb:99 ccm fir
a=rtcp-fb:99 nack
a=rtcp-fb:99 nack pli
1.2 SDP 在 WebRTC 中的作用
在 WebRTC 中,SDP 用于在通信双方之间交换音视频编解码器、传输协议、IP 地址和端口等信息。SDP 交换通常通过信令服务器进行。当一个用户想要与另一个用户建立通信连接时,首先会创建一个 SDP offer,包含自己的媒体参数和能力。然后,通过信令服务器发送给对方。接收方收到 SDP offer 后,会根据自己的能力和需求创建一个 SDP answer,并通过信令服务器发送回去。双方根据对方的 SDP 进行协商和配置,最终建立起实时通信连接。
SDP 在 WebRTC 中的主要作用有:
- 音视频编解码器协商 :通过 SDP 交换,通信双方可以了解对方支持的音视频编解码器,从而选择一个双方都支持的编解码器进行通信。
- 传输协议协商 :通过 SDP 交换,通信双方可以了解对方支持的传输协议(如 RTP、RTCP、DTLS 等),从而选择一个双方都支持的传输协议进行通信。
- ICE 候选地址交换 :通过 SDP 交换,通信双方可以互相告知自己的 ICE 候选地址(包括本地地址、反射地址和中继地址),从而协助 ICE 连接建立。
- 媒体流信息交换 :通过 SDP 交换,通信双方可以了解对方的媒体流信息(如流 ID、轨道 ID 等),从而实现多路复用和媒体流控制。
通过 SDP 在 WebRTC 中的这些作用,通信双方可以协商出合适的音视频编解码器、传输协议和网络地址,从而实现高效、稳定的实时通信。
2. 交互式连接建立(ICE)
2.1 ICE 协议简介
交互式连接建立(ICE,Interactive Connectivity Establishment)是一种用于在复杂网络环境中建立点对点连接的技术。它可以帮助 WebRTC 穿透 NAT(网络地址转换)和防火墙,从而实现实时音视频通信。ICE 的核心原理是通过尝试多种可能的网络地址和端口组合,找到一条最佳的通信路径。
在 ICE 中,每个网络地址和端口组合被称为一个候选地址(candidate)。候选地址分为三种类型:
- 主机候选地址 :来自本地设备的 IP 地址和端口。
- 服务器反射候选地址 :通过 STUN 服务器获取的公网 IP 地址和端口。
- 中继候选地址 :通过 TURN 服务器获取的中继 IP 地址和端口。
ICE 通过以下步骤进行连接建立:
- 收集候选地址 :客户端收集自己的所有候选地址(主机、服务器反射和中继地址)。
- 交换候选地址 :通过 SDP 交换,通信双方互相告知自己的候选地址。
- 连接检测 :客户端使用收到的对方候选地址和自己的候选地址进行连接测试,找到一条可用的通信路径。
- 选取最佳路径 :客户端根据连接测试的结果,选取一条最佳的通信路径。
2.2 ICE 的组件:STUN 和 TURN
ICE 主要包括两个组件:STUN(Session Traversal Utilities for NAT)和 TURN(Traversal Using Relays around NAT)。
- STUN(Session Traversal Utilities for NAT)
STUN 是一种帮助客户端穿透 NAT 的协议。当客户端位于 NAT 后时,它可以向 STUN 服务器发送请求,获取自己的公网 IP 地址和端口(即服务器反射地址)。然后,客户端将这些地址作为候选地址之一,用于 ICE 连接建立。
STUN 服务器通常部署在公网上,以便客户端可以访问。WebRTC 支持的 STUN 协议包括:RFC 3489(Classic STUN)和 RFC 5389(STUN for ICE)。 - TURN(Traversal Using Relays around NAT)
TURN 是一种用于在无法直接建立点对点连接时,通过中继服务器进行通信的协议。当客户端无法直接与对方建立连接时(例如,双方都位于对称 NAT 后),它可以请求 TURN 服务器为自己分配一个中继地址。然后,客户端将这个地址作为候选地址之一,用于 ICE 连接建立。当通信双方选中中继地址作为最佳路径时,它们的通信数据将通过 TURN 服务器中继传输。
TURN 服务器通常部署在公网上,以便客户端可以访问。WebRTC 支持的 TURN 协议包括:RFC 5766(TURN)和 RFC 6062(TURN for TCP)。
通过 STUN 和 TURN 这两个组件,ICE 可以帮助 WebRTC 穿透各种复杂的网络环境,实现稳定、高效的实时音视频通信。在接下来的两章中,我们将详细讲解 STUN 协议 和 TURN 协议的原理和用法。
3. STUN (Session Traversal Utilities for NAT)
3.1 STUN 协议简介
STUN(Session Traversal Utilities for NAT)是一种网络协议,用于解决网络地址转换(NAT)环境下的通信问题。它的主要作用是帮助客户端发现自己在NAT后面的地址和端口,以便在P2P通信中建立连接。
STUN在WebRTC中扮演着重要的角色。WebRTC是一项用于浏览器之间实时通信的技术,涉及音视频通话、文件共享等场景。然而,由于NAT的存在,直接在NAT后面的设备之间建立P2P连接变得困难。这时候,STUN协议通过帮助设备发现自己的公网IP地址和端口,以及NAT类型等信息,为WebRTC提供了解决NAT穿越的基础。
STUN消息是基于二进制格式的,具有一定的结构和字段。它通常包含以下几个重要的部分:
项目 | 描述 |
---|---|
消息头(Message Header) | 包含STUN消息的类型、长度和事务ID等信息。 |
消息体(Message Body) | 包含具体的属性信息,用于传递额外的数据。 |
消息类型(Message Type) | 表示消息的目的和作用,包括请求消息和响应消息等类型。 |
属性(Attributes) | 包含在消息体中,用于传递特定的数据,例如地址、端口、NAT类型等。 |
STUN消息的格式和字段是通过字节序列进行编码和解码的,具体的格式和字段取决于协议规范的定义。
3.2 STUN 的工作流程
STUN协议涉及客户端与服务器之间的交互流程,用于获取客户端在NAT后面的地址和端口信息。以下是STUN协议的基本流程:
序号 | 步骤 | 描述 |
---|---|---|
1 | 客户端发起请求 | 客户端向 STUN 服务器发送一个 Binding Request 消息,请求获取自己的公网 IP 地址和端口。 |
2 | STUN 服务器处理请求 | STUN 服务器收到 Binding Request 消息后,解析客户端的公网 IP 地址和端口。这些信息可以从收到的请求数据包中获取。 |
3 | 服务器响应 | STUN 服务器将客户端的公网 IP 地址和端口打包成一个 Binding Response 消息,并将该消息发送回客户端。 |
4 | 客户端处理响应 | 客户端收到 Binding Response 消息后,解析出自己的公网 IP 地址和端口。然后,将这些地址作为候选地址之一,用于 ICE 连接建立。 |
5 | 周期性检测 | 为了应对网络环境的变化,客户端需要周期性地向 STUN 服务器发送 Binding Request 消息,以获取最新的公网 IP 地址和端口。 |
STUN协议的流程可以帮助客户端绕过NAT,获得公网可达的地址和端口信息,从而实现更可靠和高效的实时通信。通过以上步骤,STUN 协议帮助客户端获取自己的公网 IP 地址和端口,并将这些地址用于 WebRTC 的 ICE 连接建立过程。这使得 WebRTC 能够在复杂的网络环境中实现稳定、高效的实时音视频通信。
3.3 STUN JavaScript 编程
3.3.1 发送和接收STUN消息
在 WebRTC 中,STUN 消息的发送和接收通常是通过 RTCPeerConnection 对象自动处理的。RTCPeerConnection 对象会根据提供的 STUN 服务器配置自动发送 STUN 绑定请求并处理响应。
以下是具体的步骤:
配置 STUN 服务器: 首先,你需要配置 STUN 服务器的地址和端口。这些信息将作为 RTCPeerConnection 对象的配置参数。
const stunServerConfig = {
iceServers: [
{
urls: 'stun:stun.rixtelecom.se',
},
],
};
创建 RTCPeerConnection 对象: 使用 STUN 服务器配置创建一个 RTCPeerConnection 对象。
const peerConnection = new RTCPeerConnection(stunServerConfig);
触发 ICE 候选收集: 为了让 RTCPeerConnection 对象与 STUN 服务器进行交互并收集 ICE 候选信息,你需要创建一个数据通道或媒体流,并设置 SDP 描述。
// 创建一个空的 DataChannel,用于触发 ICE 候选收集
peerConnection.createDataChannel('');
// 创建并设置 Offer SDP
peerConnection
.createOffer()
.then((offer) => peerConnection.setLocalDescription(offer));
监听 ICE 候选事件: RTCPeerConnection 对象会自动发送 STUN 绑定请求并处理 STUN 响应。你需要监听 onicecandidate
事件以获取 ICE 候选信息。
peerConnection.onicecandidate = function (event) {
if (event.candidate) {
console.log('ICE 候选:', event.candidate);
} else {
// ICE 候选收集完成
console.log('ICE 候选收集完成');
}
};
在这个过程中,RTCPeerConnection 对象会自动处理与 STUN 服务器的交互,包括发送 STUN 绑定请求和接收 STUN 响应。你不需要手动构造、发送或接收 STUN 消息。你只需要关注 ICE 候选事件,从中获取公网 IP 地址和端口信息。
一些补充:
- STUN 协议不是基于 HTTP 的:
STUN 是一个基于 UDP 或 TCP 的传输层协议,而不是基于 HTTP 的应用层协议。因此使用 XMLHttpRequest 对象尝试向 STUN 服务器发送请求是不合适的,同样也不能使用 基于XMLHttpRequest 封装的模块进行请求,如使用 axios。在浏览器种,你需要使用 WebRTC API 中专用的的 RTCPeerConnection 对象来处理 STUN 服务器的交互,如上面所介绍的。
3.3.2 STUN 公共服务器
公共STUN服务器是由第三方提供并开放给公众使用的服务器。这些服务器已经配置好并且可以处理STUN请求和响应。为了使用公共STUN服务器,我们需要配置服务器的地址和端口,并将其用于发送STUN请求。
在这里,已经为各位读者找到了一些免费的公共 stun 服务器:
stun.l.google.com:19302
stun1.l.google.com:19302
stun2.l.google.com:19302
stun3.l.google.com:19302
stun4.l.google.com:19302
stun.iptel.org
stun.rixtelecom.se
stun.voiparound.com
stun01.sipphone.com
stun.ekiga.net
stun.schlund.de
stun.voipbuster.com
stun.voipstunt.com
stun.voxgratia.org
stun.xten.com
stunserver.org
stun.softjoys.com
stun.fwdnet.net
stun.ideasip.com
如果有读者搭建 stun 服务器愿意公开使用也可以在留言区评论。
例如:
// STUN服务器地址和端口
var configuration = {
iceServers: [
{
urls: 'stun:stun.l.google.com:19302'
}
]
};
// 创建RTCPeerConnection对象,并传递配置对象
var peerConnection = new RTCPeerConnection(configuration);
// 创建一个虚拟的数据通道,以触发STUN服务器的连接
var channel = peerConnection.createDataChannel('stun-channel');
// 监听onicecandidate事件,获取本地候选地址
peerConnection.onicecandidate = function(event) {
if (event.candidate) {
// 处理ICE候选地址,获取IP地址信息
var ip = event.candidate.address;
console.log('本地IP地址:', ip);
}
};
// 创建一个空的SDP描述,触发ICE候选地址的收集
peerConnection.createOffer().then(function(offer) {
// 设置本地SDP描述
return peerConnection.setLocalDescription(offer);
}).catch(function(error) {
console.log('创建offer失败:', error);
});
3.4 RTCPeerConnection API 解析
3.4.1 概述
RTCPeerConnection API 是 WebRTC 的核心组件,它代表了从本地计算机到远程对等方的 WebRTC 连接,在后面的 TURN 协议种也会用到。该接口提供了创建、保持、监控和关闭连接的方法实现。其主要功能包括:
功能 | 描述 |
---|---|
创建连接 | 通过构造函数 new RTCPeerConnection() 创建一个新的 RTCPeerConnection 实例,它接受一个可选的配置对象,例如 STUN/TURN 服务器信息。 |
媒体流和数据通道 | API 提供了将本地和远程媒体流附加到连接的方法(如 addTrack() 和 addTransceiver() 方法),以及创建数据通道(createDataChannel() 方法)。 |
SDP 交换 | RTCPeerConnection 提供了创建(createOffer() 和 createAnswer() 方法)和设置(setLocalDescription() 和 setRemoteDescription() 方法 )SDP 描述的方法,以进行信令交换。 |
ICE 候选收集 | API 自动处理与 STUN/TURN 服务器的交互,如收集和发送 ICE 候选。可以通过监听 onicecandidate 事件来获取 ICE 候选信息。 |
连接状态 | RTCPeerConnection 提供了一些属性来监控连接状态,如 iceConnectionState、iceGatheringState 和 connectionState。 |
3.4.2 属性
属性 | 描述 |
---|---|
connectionState | 表示连接的当前状态,例如 new 、connecting 、connected 、disconnected 、failed 和 closed |
currentLocalDescription | 表示当前连接的本地 SDP 描述 |
currentRemoteDescription | 表示当前连接的远程 SDP 描述 |
iceConnectionState | 表示 ICE 连接的当前状态,例如 new 、checking 、connected 、completed 、failed 和 disconnected 。 |
iceGatheringState | 表示 ICE 候选收集的当前状态,例如 new 、gathering 和 complete |
localDescription | 表示已经应用到连接的本地 SDP 描述 |
pendingLocalDescription | 表示在等待应用到连接的本地 SDP 描述 |
pendingRemoteDescription | 表示在等待应用到连接的远程 SDP 描述 |
remoteDescription | 表示已经应用到连接的远程 SDP 描述 |
sctp | 表示连接的 SCTP 传输对象 |
3.4.3 方法
方法总览
方法 | 描述 |
---|---|
addIceCandidate() | 向连接添加一个新的 ICE 候选。 |
addTrack() | 向连接添加一个媒体轨道。 |
addTransceiver() | 向连接添加一个新的 RTP 发送器/接收器对。 |
close() | 关闭连接。 |
createAnswer() | 创建一个 SDP 应答。 |
createDataChannel() | 创建一个新的数据通道。 |
createOffer() | 创建一个 SDP 提议。 |
getConfiguration() | 获取连接的当前配置。 |
getReceivers() | 获取连接的所有 RTCRtpReceiver 对象。 |
getSenders() | 获取连接的所有 RTCRtpSender 对象。 |
getStats() | 获取连接的统计信息。 |
getTransceivers() | 获取连接的所有 RTCRtpTransceiver 对象。 |
removeTrack() | 从连接中移除一个媒体轨道。 |
restartIce() | 重新启动 ICE 过程。 |
setConfiguration() | 设置连接的配置。 |
setLocalDescription() | 设置本地 SDP 描述。 |
setRemoteDescription() | 设置远程 SDP 描述。 |
addIceCandidate():向连接添加一个新的 ICE 候选
peerConnection.onicecandidate = function(event) {
if (event.candidate) {
remotePeerConnection.addIceCandidate(event.candidate)
.then(function() {
console.log("添加 ICE 候选成功");
})
.catch(function(error) {
console.error("添加 ICE 候选失败", error);
});
}
};
addTrack():向连接添加一个媒体轨道
navigator.mediaDevices.getUserMedia({ audio: true, video: true })
.then(function(stream) {
stream.getTracks().forEach(function(track) {
peerConnection.addTrack(track, stream);
});
});
addTransceiver():向连接添加一个新的 RTP 发送器/接收器对
const transceiver = peerConnection.addTransceiver("audio");
close():关闭连接
peerConnection.close();
createAnswer():创建一个 SDP 应答。
peerConnection.createAnswer()
.then(function(answer) {
return peerConnection.setLocalDescription(answer);
})
.then(function() {
// 发送 answer 到远程对等端
})
.catch(function(error) {
console.error("创建应答失败", error);
});
createDataChannel():创建一个新的数据通道
const dataChannel = peerConnection.createDataChannel("myDataChannel");
createOffer():创建一个 SDP 提议
peerConnection.createOffer()
.then(function(offer) {
return peerConnection.setLocalDescription(offer);
})
.then(function() {
// 发送 offer 到远程对等端
})
.catch(function(error) {
console.error("创建提议失败", error);
});
getConfiguration():获取连接的当前配置
const configuration = peerConnection.getConfiguration();
console.log(configuration);
getReceivers():获取连接的所有 RTCRtpReceiver 对象
const receivers = peerConnection.getReceivers();
console.log(receivers);
getSenders():获取连接的所有 RTCRtpSender 对象
const senders = peerConnection.getSenders();
console.log(senders);
getStats():获取连接的统计信息
peerConnection.getStats()
.then(function(stats) {
console.log(stats);
});
getTransceivers():获取连接的所有 RTCRtpTransceiver 对象
const transceivers = peerConnection.getTransceivers();
console.log(transceivers);
removeTrack():从连接中移除一个媒体轨道
const senders = peerConnection.getSenders();
peerConnection.removeTrack(senders[0]);
restartIce():重新启动 ICE 过程
peerConnection.restartIce();
setConfiguration():设置连接的配置
const newConfiguration = { iceServers: [{ urls: "stun:stun.example.org" }] };
peerConnection.setConfiguration(newConfiguration);
setLocalDescription():设置本地 SDP 描述
peerConnection.createOffer()
.then(function(offer) {
return peerConnection.setLocalDescription(offer);
})
.catch(function(error) {
console.error("设置本地描述失败", error);
});
setRemoteDescription():设置远程 SDP 描述
// 假设 remoteOffer 是从远程对等端接收到的 SDP 提议
peerConnection.setRemoteDescription(remoteOffer)
.then(function() {
// 远程描述设置成功
})
.catch(function(error) {
console.error("设置远程描述失败", error);
});
3.4.4 事件处理程序
在 RTCPeerConnection 对象的上下文中,事件处理程序是在对象的特定属性发生变化时触发的函数。例如当 connectionState
属性发生变化时,onconnectionstatechange
事件处理程序将被触。
方法 | 描述 |
---|---|
onconnectionstatechange | 当 connectionState 属性发生变化时触发 |
ondatachannel | 当新的数据通道被创建时触发 |
onicecandidate | 当新的 ICE 候选可用时触发 |
onicecandidateerror | 是一个事件处理程序,它在 ICE 候选收集过程中出现错误时触发。当 WebRTC 使用 ICE 框架在对等连接中建立连接时,它会收集可用的网络候选(即可能的网络地址和端口)并与远程对等方交换这些候选。如果在收集或处理这些候选时发生错误,onicecandidateerror 事件处理程序将被触发。 |
oniceconnectionstatechange | 当 iceConnectionState 属性发生变化时触发 |
onicegatheringstatechange | 当 iceGatheringState 属性发生变化时触发。iceGatheringState 属性表示 ICE 候选收集过程的当前状态,可能的值包括:new、gathering 和 complete。 |
onnegotiationneeded | 当需要重新协商连接时触发 |
onsignalingstatechange | 是收到 signalingstatechange 事件时调用的事件处理器,当signalingState 的值发生改变时,该事件被触发。 |
onstatsended | 当统计信息结束时触发 |
ontrack | 当新的媒体轨道被添加到连接时触发 |
例如:
const pc = new RTCPeerConnection();
pc.onconnectionstatechange = function (event) {
console.log("连接状态已更改为:", pc.connectionState);
if (pc.connectionState === "connected") {
console.log("连接建立!");
} else if (pc.connectionState === "failed") {
console.error("连接失败!");
}
};
// 其他 RTCPeerConnection 代码...
本例中,当连接状态发生变化时,会将新的状态记录到控制台。
- 如果连接成功建立,将输出 “连接建立!”;
- 如果连接失败,则输出 “连接失败!”。
又如:
const pc = new RTCPeerConnection();
pc.onicecandidateerror = function (event) {
console.error("ICE候选错误:", event);
// 在这里处理错误,例如向用户显示错误消息
};
// 其他 RTCPeerConnection 代码...
这个例子中,当发生 ICE 候选错误时,将错误事件记录到控制台。
再如:
const pc = new RTCPeerConnection();
pc.onicegatheringstatechange = function (event) {
console.log("ICE收集状态已更改为:", pc.iceGatheringState);
if (pc.iceGatheringState === "gathering") {
console.log("ICE开始收集。");
} else if (pc.iceGatheringState === "complete") {
console.log("ICE收集完成。");
// 在这里处理收集完成后的操作,例如发送ICE候选给远程对等方
}
};
// 其他 RTCPeerConnection 代码...
这个例子中,当 ICE 收集状态发生变化时,会将新的状态记录到控制台。
- 如果收集开始,将输出 “ICE开始收集。”;
- 如果收集完成,则输出 “ICE收集完成。”。
4. TURN (Traversal Using Relays around NAT)
4.1 TURN 协议简介
TURN(Traversal Using Relays around NAT)是一种用于在 NAT(网络地址转换)环境中实现穿越的协议。在某些情况下,STUN 服务器无法帮助客户端建立直接的 P2P 连接。这时,TURN 协议就派上了用场。TURN 协议通过在客户端之间引入一个中继服务器来传输数据,从而实现 WebRTC 通信。
TURN 的原理是在客户端之间建立一个中继服务器,用于转发音频、视频和数据流。当客户端无法直接建立 P2P 连接时,TURN 服务器会充当中继节点,将数据从一个客户端转发到另一个客户端。这样,即使客户端位于复杂的 NAT 环境中,也能实现实时音视频通信。
4.2 TURN 的工作流程
TURN 的工作流程主要分为以下几个步骤:
序号 | 步骤 | 描述 |
---|---|---|
1 | 客户端发起请求 | 客户端向 TURN 服务器发送一个 Allocate Request 消息,请求分配一个中继地址。 |
2 | TURN 服务器处理请求 | TURN 服务器收到 Allocate Request 消息后,为客户端分配一个中继地址(IP 地址和端口),并将该地址与客户端的公网地址绑定。 |
3 | 服务器响应 | TURN 服务器将分配的中继地址打包成一个 Allocate Response 消息,并将该消息发送回客户端。 |
4 | 客户端处理响应 | 客户端收到 Allocate Response 消息后,解析出分配的中继地址。然后,将这些地址作为候选地址之一,用于 ICE 连接建立。 |
5 | 数据转发 | 在 ICE 连接建立过程中,如果客户端无法直接建立 P2P 连接,就会选择使用 TURN 服务器作为中继。此时,客户端将音频、视频和数据流发送到分配的中继地址,TURN 服务器再将这些数据转发给另一个客户端。 |
6 | 周期性检测 | 为了应对网络环境的变化,客户端需要周期性地向 TURN 服务器发送 Allocate Request 消息,以获取最新的中继地址。 |
通过以上步骤,TURN 协议帮助客户端在无法直接建立 P2P 连接的情况下,通过中继服务器实现实时音视频通信。这使得 WebRTC 能够在复杂的网络环境中实现稳定、高效的实时音视频通信。
4.3 TURN 相关编程实践
待补充
附. 积极拥抱 IPv6 的倡议
F.1 IPv4危机 之 地址耗尽
F.1.1 IPv4 地址的耗尽
拥有大约43亿个唯一地址的IPv4地址空间曾经被认为是绰绰有余的。然而,互联网的快速增长和互联网连接设备的激增导致了IPv4地址的短缺。互联网数字地址分配机构(IANA)在2011年分配了最后一个IPv4地址块,促使人们需要一个替代的寻址系统。
F.1.2 NAT 和 DHCP技术的应用
为了解决 IPv4 危机,开发了 网络地址转换(NAT) 和 动态主机配置协议(DHCP) 等技术。NAT允许多个设备通过将私有IP地址转换为公共IP地址来共享一个公共IPv4地址。DHCP为网络上的设备动态分配IP地址,从而有效利用有限的IPv4资源。
这些技术缓解了 IPv4 危机,但它们不是长期的解决方案。
F.2 IPv4危机 之 安全担忧
F.2.1 美国控制下的 IPv4 跟根务器
美国对管理全球域名系统(DNS)的13个根服务器拥有重大控制权,其中10个位于US.DNS对于互联网的运行至关重要,因为它将人类可读的域名转换为IP地址。通过控制根服务器,美国有可能操纵或破坏全球互联网服务。
正如棱镜门事件所揭示,美国将网络战和监控作为其军事和情报行动的一部分。例如,被广泛认为是由美国和以色列开发的Stuxnet蠕虫病毒,目标就是伊朗的核program。此外,美国国家安全局(NSA)进行了广泛的全球监控。
美国对 IPv4 根服务器的控制及其对网络战和监控的参与引发了对全球安全和美国信任的担忧,尤其是棱镜门事件之后,包括默克尔等大量被视作美国盟友的西方国家政要被无差别监听的消息引来了全世界的指责。不仅是中国,同时包括美国在欧洲的盟友,对美国在互联网监管方面的主导地位以及美国利用这种控制为政治或军事目服务的可能性表示了广泛的担忧。
F.2.2 美国对IPv4根服务器控制的妥协
作为对这些担忧的回应,2016年年美国政府允许其与互联网名称与数字地址分配机构(ICANN)的合同到期,有效地将互联网数字地址分配机构(IANA)职能的监督权转移给了全球多利益主体社区。
F.2.3 不安全因素并未抹去
尽管美国已经通过允许与 ICANN 的合同到期来减少对互联网治理的控制,但由于 ICANN 与美国的联系、互联网治理中透明度和包容性的缺失、持续的网络战和监控活动以及地缘政治紧张局势加剧,全球担忧仍然存在。
-
ICANN 与美国的联系: 虽然美国政府在 2016 年允许与 ICANN 的合同到期,将 IANA 功能的监督转交给全球多方利益攸关者社区,但由于 ICANN 与美国的历史和法律联系,人们仍然感到担忧。ICANN 是一家总部位于加利福尼亚的非营利组织,其法律管辖区在美国。这种联系引发了关于美国政府可能仍然对 ICANN 及其决策过程施加影响的问题。
-
互联网治理透明度和包容性的缺失: 尽管似乎美国已经让多方利益攸关者参与其中,但当前的互联网治理模式仍缺乏足够的透明度和包容性。西方国家和企业在互联网治理机构(如 ICANN)中的主导地位加剧了这些担忧,导致人们呼吁在互联网治理中实现权力更加公平的分配。
-
持续的网络战和监控活动: 美国参与了网络战和全球监控,例如 Stuxnet(蠕虫病毒) 和 Prism Gate(棱镜门) 等事件。这些活动导致其他国家,特别是与美国关系紧张的国家,感到不信任和不安。即使美国已经努力减少对互联网治理的控制,其持续参与网络活动仍可能加剧担忧。
-
地缘政治紧张局势和数字主权的推动: 美国和中国等大国之间日益加剧的地缘政治紧张局势导致了对数字主权的推动。各国寻求更大程度地控制其国内互联网基础设施,以保护国家利益,减少对外国实体的依赖,并降低因互联网资源集中控制而产生的潜在风险。
种种这些因素导致了对数字主权的推动和替代互联网基础设施的发展,例如中国采用 IPv6。
F.3 中国 IPv6 发展历程
中国IPv6的发展历程可以分为以下几个阶段:
- 早期探索阶段:中国在1990年代末期开始关注IPv6技术。在2003年,中国互联网协会IPv6工作组成立,标志着中国正式启动IPv6技术研究和试验工作。
- 积极推进阶段:2017年,中国政府发布了《推进互联网协议第六版(IPv6)规模部署行动计划》,明确了IPv6的发展方向和阶段目标。此后,中国在IPv6的建设和发展上取得了显著成果,如2020年10月,IPv6活跃用户数达到4.37亿,占比48.30%。
- 规模化部署阶段:2021年,中国IPv6发展取得明显进展,如IPv6活跃用户数持续上升,LTE网络和宽带接入网络大规模分配IPv6地址。
F.4 《推进互联网协议第六版(IPv6)规模部署行动计划》的出台
国内早期各大路由设备厂商默认关闭 IPv6 因为当时各大厂商 IPv6 尚未达到与IPv4一样的体验。但是目前 IPv6 相关技术已经成熟,如果所有厂商持续采取消极态度不利于国家安全和国家战略。积极推动 IPv6 的发展,不仅有助于提升国家竞争力和网络主权,还能推动数字经济和信息产业的发展。
日前 IPv6 已成为全球互联网发展的趋势,包括中国在内的各国都纷纷推动 IPv6 的部署。中国希望通过积极推广 IPv6,提升国家的国际竞争力,并在互联网领域的技术创新上占据重要地位。《推进互联网协议第六版(IPv6)规模部署行动计划》(以下简称“该计划”)。
在该计划提出的目标之一是:
“到2025年末,我国IPv6网络规模、用户规模、流量规模位居世界第一位,网络、应用、终端全面支持IPv6,全面完成向下一代互联网的平滑演进升级,形成全球领先的下一代互联网技术产业体系。”
目前国家正在努力升级改造广电网络。“以全国有线电视互联互通平台建设为契机,加快推动广播电视领域平台、网络、终端等支持IPv6,促进文化传媒领域业务创新升级。”
作为普通开发者,不论是站在技术发展的大潮流,还是响应国家号召,都应该积极拥抱国家政策,响应国家号召,针对 IPv6 技术做必要的学习、了解以及应用于生产实践。
F.5 从 WebRTC 角度看 IPv6
IPv6 技术为 WebRTC 带来了诸多变革,包括更多的地址空间、改进的连接建立、更好的网络性能、增强的安全性和更好的移动性。这些变革有助于提高 WebRTC 在实时通信场景中的可靠性和性能:
-
更多的地址空间: IPv6 提供了几乎无限的地址空间,这意味着每个设备都可以拥有一个唯一的公共 IP 地址。在 WebRTC 的场景中,这消除了 NAT(网络地址转换)的需要,从而简化了端到端通信的建立过程。在 IPv4 中,NAT 通常会导致连接失败或者需要额外的技术(如 STUN、TURN 服务器)来解决这些问题。
-
改进的连接建立: 由于 IPv6 减少了 NAT 的使用,WebRTC 中的连接建立过程可以更加简便,降低了连接失败的可能性。同时,IPv6 支持端到端的直接通信,可以提高连接质量和性能。
-
更好的网络性能: IPv6 提供了一些改进的网络功能,如流标签、IPv6 分片和底层 QoS(Quality of Service)支持。这些功能有助于提高 WebRTC 通话的质量和稳定性。
-
增强的安全性: IPv6 支持 IPsec(Internet Protocol Security),这是一种用于在 IP 层加密和认证数据的协议。在 WebRTC 场景中,这可以提供更强大的安全性,保护通信不被窃听或篡改。
-
更好的移动性: IPv6 支持移动 IPv6(MIPv6)技术,允许设备在不同网络间无缝漫游。对于 WebRTC 来说,这意味着用户在移动过程中可以更容易地保持音视频通话的稳定性。