WebRTC 协议介绍--一篇读懂ICESTUN NAT TURN

Posted 一苇渡江694

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WebRTC 协议介绍--一篇读懂ICESTUN NAT TURN相关的知识,希望对你有一定的参考价值。

要想了解ICE,必须先了解NAT

NAT

网络地址转换(英语:Network Address Translation,缩写:NAT;又称网络掩蔽、IP掩蔽)在计算机网络中是一种在IP数据包通过路由器或防火墙时重写来源IP地址或目的IP地址的技术。这种技术被普遍使用在有多台主机但只通过一个公有IP地址访问互联网的私有网络中。它是一个方便且得到了广泛应用的技术。当然,NAT也让主机之间的通信变得复杂,导致了通信效率的降低。

为什么会存在公网IP和局域网IP。
我们知道由于IPv4的地址是有限制的,因此不可能给世界上所有的设备分配一个公网地址,NAT便是缓解IPv4地址耗尽的一种方法。
同时,NAT还可以保证局域网的设备有一定的安全性。

ICE

交互式连接创建(Interactive Connectivity Establishment),一种综合性的NAT穿越的技术。

交互式连接创建是由IETF的MMUSIC工作组开发出来的一种framework,可集成各种NAT穿透技术,如STUN、TURN(Traversal Using Relay NAT,中继NAT实现的穿透)、RSIP(Realm Specific IP,特定域IP)等。该framework可以让SIP的客户端利用各种NAT穿透方式打穿远程的防火墙。

交互式连接设施Interactive Connectivity Establishment (ICE) 是一个允许你的浏览器和对端浏览器建立连接的协议框架。在实际的网络当中,有很多原因能导致简单的从A端到B端直连不能如愿完成。这需要绕过阻止建立连接的防火墙,给你的设备分配一个唯一可见的地址(通常情况下我们的大部分设备没有一个固定的公网地址),如果路由器不允许主机直连,还得通过一台服务器转发数据。ICE通过使用以下几种技术完成上述工作。

STUN

STUN(Session Traversal Utilities for NAT,NAT会话穿越应用程序)是一种网络协议,它允许位于NAT(或多重NAT)后的客户端找出自己的公网地址,查出自己位于哪种类型的NAT之后以及NAT为某一个本地端口所绑定的Internet端端口。这些信息被用来在两个同时处于NAT路由器之后的主机之间创建UDP通信。该协议由RFC 5389定义。

STUN技术需要一个位于公网的STUN server,它实现了一个基于client-server的协议(该协议见RFC5389),由客户端主动发起连接,STUN server会通知STUN client它的公网IP以及公网端口。在VOIP场景,STUN client可以将公网IP以SIP消息方式通知到另一端,这样即使这个客户度没有向另一个客户度的发送UDP报文,另一端就可以主动向这个客户端发送UDP报文。

TURN

TURN(全名Traversal Using Relay NAT),是一种资料传输协议(data-transfer protocol)。允许在TCP或UDP的连在线跨越NAT或防火墙。

TURN是一个client-server协议。TURN的NAT穿透方法与STUN类似,都是通过获取应用层中的公有地址达到NAT穿透。但实现TURN client的终端必须在通信开始前与TURN server进行交互,并要求TURN server产生"relay port",也就是relayed-transport-address。这时TURN server会创建peer,即远程端点(remote endpoints),开始进行中继(relay)的动作,TURN client利用relay port将资料发送至peer,再由peer转传到另一方的TURN client。

TURN是另外一个技术,可以用来解决STUN不能解决的问题,通常在STUN不可用的时候可以使用TURN。

最终ICE

搜集地址:
通话前先搜集本地的IP和端口号(Candidate),然后拿这些candiate和STUN server通信,得到可用的candidate以及对应的公网IP和端口号。
然后再访问TURN server得到所有中继Candidate以及公网IP和端口。

通过上述的步骤,可以得到这个candiate是哪个网卡的,是否存在NAT,可以得到是否是relay。搜集到candidate后需要给这些candidate分配优先级。通常来说,中继candidate优先级最低。如果存在多张网卡,也会有一些偏好,如VPN优先级会高一点。拿到这些地址后,就可以填充到SIP消息中,ICE扩展了SDP,增加了新的candidate属性,列出了所有candidate的IP、端口、优先级、类型。

检查连接:
主叫和被叫已经交换了SDP,拿到对方candidate后,使用这些地址发送STUN消息检查连接。比如被叫选择自己的一个candidate和主叫的candidate,利用这个连接发送一条STUN消息给主叫,主叫收到后恢复STUN消息表明自己已经收到,如果被叫能够收到这条消息,那么被叫就能发送报文到主叫了。此时,这样一来一回地通信可以检查,主叫和被叫在这个连接中是双向互通的。这里STUN消息和媒体流使用相同的IP和端口,也就意味着这个IP和端口需要复用。

完成:
检查完成后,客户端会拿第一个完成的candidate用于通信,第一个完成的通常也是优先级最高的。最终,客户端会完成最后一次确认,确认这个candidate对是最终选择的,后续的通信会使用这个candidate对,不会有任何不明确。

监听连接状态
继承class PeerConnectionObserver,监听OnConnectionChange(
webrtc::PeerConnectionInterface::PeerConnectionState new_state)
通过new_state来判断连接状态:

enum class PeerConnectionState 
    kNew,
    kConnecting,
    kConnected,
    kDisconnected,
    kFailed,
    kClosed,
  ;

SDP中的candidate

Candidate 分为四类

  • host
  • srflx
  • relay
  • prflx
candidate-attribute   = "candidate" ":" foundation SP component-id SP
                        transport SP
                        priority SP
                        connection-address SP     ;from RFC 4566
                        port         ;port from RFC 4566
                        SP cand-type
                        [SP rel-addr]
                        [SP rel-port]
                        *(SP extension-att-name SP
                             extension-att-value)


foundation            = 1*32ice-char
component-id          = 1*5DIGIT
transport             = "UDP" / transport-extension
transport-extension   = token              ; from RFC 3261
priority              = 1*10DIGIT
cand-type             = "typ" SP candidate-types
candidate-types       = "host" / "srflx" / "prflx" / "relay" / token
rel-addr              = "raddr" SP connection-address
rel-port              = "rport" SP port
extension-att-name    = token
extension-att-value   = *VCHAR
ice-char              = ALPHA / DIGIT / "+" / "/"

例如:

a=candidate:1 1 UDP 9654321 212.223.223.223 12345 typ srflx raddr 10.216.33.9 rport 54321

a=ice-ufrag:5260_1082852_1
a=ice-pwd:9f2efd5e6fcf424c62d33e50b702cf19

foundation为1,媒体是RTP,采用UDP协议,公网映射地址为212.223.223.223:12345,优先级为9654321,type为srflx,base地址为10.216.33.9:54321

SFU下的ICE

  1. 通过自己的信令服务器,获取candidate ip
  2. candidate ip设置到remote sdp中
  3. 省略stun,直接使用turn协议

SFU 模式下,SFU 服务都会有自己的固定公网IP地址,这个先决条件简化了 WebRTC 中 peerConnection 的建立过程,可以把这种场景理解为 P2P 通信的一端确定在 NAT 前面,并且有固定IP地址的特殊情况,这时对于 SFU 服务没有必要再去收集自己的 iceCandidate,所以 ICE 协议(RFC5245) 中定义了一种 lite 实现方式,简化了有固定IP公网地址一端的 ice 实现方式,只要满足固定公网IP的前提条件,通过 lite 方式实现一个 ice server,完全实现 ice 协议的对端将毫无感知的与 lite 实现建立常规的 peerConnection 通信信道。

a=ice-lite

“ice-lite” is a session-level attribute only, and indicates that an agent is a lite implementation.
ice-lite 有以下几个特点:

  1. ICE 的 Lite 实现不需要实现 Candidate 的收集过程;只需要提供 Host Candidate;
  2. 不需要实现连通性检查或者状态机,只需要实现连通性检查的Response;
  3. ICE Lite 在交互过程中只能是 controlled 角色,并且不能使用 USE-CANDIDATE 来做 ice nomination;
    常规的 SFU 都会自身集成一个 ice lite 实现的 ice server,所以交互过程中省去了 ice server 的独立角色。SFU 的 SDP 信息中会携带自身的 Host Candidate 和 ‘a=ice-lite’ 属性,当对端收到 ‘a=ice-lite’ 属性后会自动将自己设置成 controlling 角色,主动与 SFU 的 ice agent 进行交互。同时 SFU 也不需要对端的 iceCandidate 信息,因为在对端发起 stun binding 测试连通性的时候就可以获取对端的信息,便可以建议一个 Transport tuple 用来维持 peerConnection 通信。
a=candidate:73095809 1 udp 1518280447 182.92.240.33 28000 typ host generation 0
network_thread_线程
JsepTransportController::AddRemoteCandidates
JsepTransport::AddRemoteCandidates
transport->internal()->ice_transport()->AddRemoteCandidate(candidate);
P2PTransportChannel::AddRemoteCandidate
P2PTransportChannel::AddRemoteCandidateWithResolver
P2PTransportChannel::FinishAddingRemoteCandidate
P2PTransportChannel::CreateConnections(const Candidate& remote_candidate,
                                            PortInterface* origin_port)
P2PTransportChannel::CreateConnection
Connection* connection = port->CreateConnection(remote_candidate, origin);


UDPPort::CreateConnection
Connection* conn = new ProxyConnection(this, 0, address);
ProxyConnection::ProxyConnection(Port* port,
                                 size_t index,
                                 const Candidate& remote_candidate)
Connection::Connection(Port* port,
                       size_t index,
                       const Candidate& remote_candidate)

以上是关于WebRTC 协议介绍--一篇读懂ICESTUN NAT TURN的主要内容,如果未能解决你的问题,请参考以下文章

WebRTC 协议介绍--一篇读懂DTLSSRTPSRTCP

WebRTC 核心功能介绍--一篇读懂SDP PlanB UnifiedPlan(从PlanB迁移到UnifiedPlan)

WebRTC 核心功能介绍--一篇读懂PeerConnectionFactoryInterface RTCConfiguration PeerConnectionInterface

WebRTC 概念介绍--一篇读懂sourcetracksinkmediastream

WebRTC 概念介绍--一篇读懂sourcetracksinkmediastream

WebRTC Native M96版本开篇之旅--一篇读懂代码下载编译(ninja gn depot_tools)