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
- 通过自己的信令服务器,获取candidate ip
- candidate ip设置到remote sdp中
- 省略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 有以下几个特点:
- ICE 的 Lite 实现不需要实现 Candidate 的收集过程;只需要提供 Host Candidate;
- 不需要实现连通性检查或者状态机,只需要实现连通性检查的Response;
- 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