浅析 P2P 穿越 NAT 的原理、技术、方法 ( 下 )

接《浅析 P2P 穿越 NAT 的原理、技术、方法 ( 上 )

3.3.2.2.1 网络拓扑类型一:

如下图所,Client A 位于NAT内网,而Client B是具有公网IP的机器。如果是Client A需要连接Client B那么Client A直接连Client B就可以了。如果Client B需要连接Client A,那么Client B直接Connect Client A一般是连接不上的。但是我们可以反过来让Client A主动去连Client B不就可以了。下面所说的Client A或Client B的NAT类型指的是对于Server S能看到的Client的最外层的NAT的类型。

反过来让Client A主动去连Client B的技术就是所谓的:反向连接技术 具体的穿越过程如下:


[1] Client B通过ConnectB1向Server S发送请求,请求连接Client A。
[2] Server S按需回复看是否需要启动Client B的NAT类型侦测。(这要看Server S是否已经缓存了Client B的相关NAT信息)
[3] Server S通过[2]可以知道Client B具有公网IP,于是,Server S通过ConnectA1发送指令给Client A让Client A主动连Client B并告诉Client A目标Client B的IPB和监听端口PortB。
[4] Client A收到Client B的IPB和监听端口PortB,然后发送连接请求连上Cient A并附带一下身份信息,于是两者就可以进行通信。

下面为了描述简便,具体的NAT侦测步骤就省略了。

3.3.2.2.2 网络拓扑类型二

如下图,Client A和Client B位于同一个NAT后面,这个时候Client A和 Client B位于同一个局域网。

具体的穿越过程如下:


[1] Client A通过ConnectA1向Server S发送请求,请求连接Client B。
[2] Server S发现Client A、B位于同一个NAT后面,于是返回Client A、Client B的公网EndpointGA、EndpointGB和内网EndpointPA、EndpointPB给Client A
[3] Client A收到后,知道Client B和自己位于同一个NAT里面,于是直接连上Client B的内网EndpointPB进行通信。

3.3.2.2.3 网络拓扑类型三

如下图,Client A和Client B分别位于不同的NAT后面,这个时候Client A和 Client B位于独立的局域网。

具体的穿越过程如下:


[1] Client A通过ConnectA1向Server S发送请求,请求连接Client B。
[2] Server S发现Client A、B位于独立的NAT后面,也是通过ConnectA1返回给Client A、Client B的公网EndpointGA、EndpointGB和内网EndpointPA、EndpointPA给Client A。并且通过ConnectB1返回给Client A、Client B的公网EndpointGA、EndpointGB和内网EndpointPA、EndpointPB给Client B。

接下来的步骤和Client A、Client B的NAT类型密切相关,下面会分别就相应的组合进行介绍具体的过程步骤。

(1)Client A是任意类型NAT,Client B 是Full Cone NAT(Endpoint Independent Mapping和Endpoint-Independent Filtering)

Full Cone NAT一般是比较少的,因为这样的NAT安全性很差。

[3] Server S通过ConnectA1发送指令让Client A直接Connect Client B的外网EndpointGB,由于Client B的NAT是Full Cone,于是NAT不管三七二十一就把收到的包转发给Client B,于是它们就可以顺利通信了。

(2)Client A是任意类型NAT,Client B 是Restricted Cone NAT(Endpoint Independent Mapping和Address-Dependent Filtering)

[3] Server S通过ConnectB1发送指令让Client B 先bind内网EndpointPB然后往Client A的外网EndpointGA发送Connect请求(由于Client B是Endpoint Independent Mapping,那么EndpointPB依旧是映射为EndpointGB),如果连接建立成功,那么它们就可以进行通信了,反之失败的话,Client B将失败结果反馈给Server S,然后转入[4]

[4] Server S收到失败反馈,通过ConnectA1发送指令让Client A往Client B的外网EndpointGB发送Connect请求,由于在步骤[3],Client B已经往Client A发送过数据包,根据过滤规则(Address-Dependent Filtering),Client B的NAT会允许Client A的数据包通过NAT并转发给Client B。于是,它们就建立其连接进行通信。

(3)Client A的NAT类型:映射规则是(Endpoint Independent Mapping)的,过滤规则任意;Client B 是Port Restricted Cone NAT(Endpoint Independent Mapping和Address and Port-Dependent Filtering)

[3] 该步骤和情况(2)中的步骤[3]完全一样
[4] Server S收到失败反馈,通过ConnectA1发送指令让Client A 先bind内网EndpointPA然后往Client B的外网EndpointGB发送Connect请求(由于Client A是Endpoint Independent Mapping,那么EndpointPA依旧是映射为EndpointGA),由于在步骤[3],Client B已经往Client A的EndpointGA发送过数据包,根据过滤规则(Address and Port-Dependent Filtering),Client B的NAT会允许Client A的EndpointGA的数据包通过NAT并转发给Client B。于是,它们就建立其连接进行通信。

(4)Client A的NAT类型:映射规则是(非Endpoint Independent Mapping)的,过滤规则任意;Client B 是Port Restricted Cone NAT(Endpoint Independent Mapping和Address and Port-Dependent Filtering)

在这种情况下,在上面的步骤[4]的时候,由于Client A是非Endpoint Independent Mapping,那么EndpointPA就会映射为是EndpointGA_B而不是EndpointGA了。这样根据过滤 规则(Address and Port-Dependent Filtering),Client B的NAT将不会允许Client A的EndpointGA_B的数据包通过NAT。要想数据包能通过Client B的NAT,需要Client B曾经给EndpointGA_B发送过数据。但是,我们无法通过直接的方法让Client B提前知道Client A的外网EndpointGA_B,难道就无能为力了吗?不,还是有些方法的,虽然无法直接知道Client A的外网EndpointGA_B,但是我们可以进行预测。具体过程如下:

[3] 该步骤和情况(2)中的步骤[3]完全一样
[4] Server S收到失败反馈,通过ConnectA1发送指令让Client A 启动端口映射预测过程。端口映射预测可以简单、可以复杂,大体就是让Client A往Server的不同端口、不同ip发送数据包,以便Server收集到Client A的端口映射样本,以便能够根据样本的端口映射变化规律预测Client A的NAT的Mapping规则。

[5] Server S根据[4]的预测情况,通过ConnectB1发送给Client B接下来Client A可能的映射端口列表也就是可能的外网EndpointGA1、EndpointGA2 ... EndpointGAn,然后让Client B都往这些外网EndpointGA1、EndpointGA2 ... EndpointGAn发送数据包。

[6] 然后Server S通过ConnectA1发送指令让Client A 先bind内网EndpointPA然后往Client B的外网EndpointGB发送Connect请求(这个时候,假设预测算法有效的话,那么Client A的内网EndpointPA将会映射为EndpointGAi),由于在步骤[5],Client B已经往Client A的EndpointGAi发送过数据包,根据过滤规则(Address and Port-Dependent Filtering),Client B的NAT会允许Client A的EndpointGAi的数据包通过NAT并转发给Client B。于是,它们就建立其连接进行通信。

[7] 如果在步骤[4]的预测失败,那么在步骤[6]将建立连接失败,然后Client B将失败结果反馈给Server S。这个时候Server S可以启动重试步骤[4][5][6]或直接判断Client A和Client B无法建立直接的P2P通信了,于是进入Relay(服务器中转)环节。Realy部分在后面会单独介绍。

3.3.2.2.4 网络拓扑类型四

如下图,Client A和 Client B位于多层NAT后面。

具体过程如下:

[1] Client A通过ConnectA1向Server S发送请求,请求连接Client B。
[2] Server S发现Client A、B位于同一个NAT后面,于是返回Client A、Client B的公网EndpointGA、EndpointGB和内网EndpointPA、EndpointPB给Client A
[3] Client A收到后,认为Client B和自己位于同一个NAT里面,于是往Client B的内网EndpointPB发送连接请求,当然是连接不上的。
[4] 在连接失败后,接着Client A尝试向Client B的外网EndpointGB发送连接请求,这个时候NAT C收到数据包后是否转发该数据包要看NAT C是否支持回环转换(hairpin translation),如果不支持那么就无法进行直连P2P通信,需要就需要反馈给Server S开启Relay。

[5] 在步骤[4]失败了,Client A是无法知道是因为NAT C不支持回环转换造成的失败,还是内层NAT的行为造成的失败。于是Client A就假设NAT C是支持回环转换的,这个时候网络拓扑情况就变成网络拓扑类型三了,那么接下来的穿越步骤就和网络拓扑类型三的多种情况一样的了,这里就不重复了。

上图,只是给出了Client A、Client B位于两层NAT后面的一种情况,对于多层NAT的各种组合本文就不介绍了。对于多层NAT的组合,在穿透失败的时候,是比较难判断出到底是哪层NAT的行为造成的。我们只能用上面说过的所有方法进行逐一重试,如果还是失败,那只能启动Relay进行服务器中转了。

3.4 Relay服务器中转技术

由于进行P2P穿透是否成功与NAT的行为和防火墙策略有很大的关系,因此就算是一个P2P友好NAT也很难保证100%穿透成功。举个例子:3.3.2.2.4 网络拓扑类型四,假设NAT A、NAT B 、NAT C都是Full Cone NAT(完全锥型),但是如果NAT C不支持回环转换(hairpin translation)那么也是无法穿透成功的。那么一个完整的P2P穿透的解决方案必不可少的一个部分就是relay了,relay部分主要TURN协议描述。作为STUN协议的一个补充,TURN协议主要由RFC5766、RFC6062、RFC6156来描述,其中RFC5766主要描述的是UDP协议的relay,RFC6062描述的是TCP协议(IPV4)的relay,而RFC6156描述的是IPV6的relay。下面主要介绍一下RFC5766和RFC6062两个文档中描述的较为重要的交互过程,具体的协议相关属性、报文结构等等,有兴趣的可以细读一下协议文档。

TURN协议简单的来讲,如下图所示:client向turn server发送一个Allocation request请求一个分配(allocation),如果turn server接收请求就会给client分配一个relay地址(IP_RELAYA:PORT_RELAYA),每个allocation都有一个有效期,过了有效期就不能使用了。在有效期内client可以发送refresh request来刷新延长有效期。Client A想给peer A发送数据需要创建权限,这个通过createPermission request请求来创建权限,权限创建成功后,client A就可以发送数据给turn server由turn server中转给peer A,同时peer A发送给turn server数据也会被turn server中转给client A。如图中所示,由于client 没有注册peer B的权限,那么client 发给peer B的数据会被turn server丢弃,同时peer B发给client 的数据也会被turn server丢弃。

3.4.1 UDP协议的Relay

首先介绍RFC5766,UDP协议的relay,主要有两种方式:第一种是Send and Data methods,第二种是channels。下面分别介绍这两个方式。

3.4.1.1 方式一、Send and Data methods,具体交互过程如下:

(1)首先client发送Allocate request 给TURN server 请求一个分配。其中携带的主要属性: Transaction-Id=0xA56250D3F17ABE679422DE85 :事务ID用于标识一个交互过程 SOFTWARE="Example client, version 1.03" :可有可无的属性 LIFETIME=3600 (1 hour) :请求分配的有效期,期望有效期 REQUESTED-TRANSPORT=17 (UDP) :未来数据传输采用的协议 DONT-FRAGMENT :请求不要将数据进行分割分包转发给PEER。

(2)TURN server回复一个Allocate error response响应,表示请求未通过授权,需要进行用户验证。 Transaction-Id=0xA56250D3F17ABE679422DE85 :事务ID要和(1)的一样 SOFTWARE="Example server, version 1.17" :可有可无 ERROR-CODE=401 (Unauthorized) :错误码 REALM="example.com" :为了让客户端下次请求的时候要带上这个属性 NONCE="adl7W7PeDU4hKE72jdaQvbAMcr6h39sm" :为了让客户端下次请求的时候要带上这个属性

(3)Client收到响应后,发现是401错误响应,那么需要给TURN server提供用户名和密码进行验证。于是client重新发送Allocate request请求。 Transaction-Id=0xC271E932AD7446A32C234492 :另起一个事务,标识另外一个请求过程 SOFTWARE="Example client 1.03" :同(1) LIFETIME=3600 (1 hour) :同(1) REQUESTED-TRANSPORT=17 (UDP) :同(1) DONT-FRAGMENT :同(1) USERNAME="George" :client的用户名 REALM="example.com" :(2)中TURN server响应给client的 NONCE="adl7W7PeDU4hKE72jdaQvbAMcr6h39sm" :(2)中TURN server响应给client的 MESSAGE-INTEGRITY=... :一些加密信息,用于验证client的

(4)TURN server 验证client通过后给client响应Allocate success response Transaction-Id=0xC271E932AD7446A32C234492 :事务ID要和(3)相同 SOFTWARE="Example server, version 1.17" :同(3) LIFETIME=1200 (20 minutes) :该分配的有效期,实际有效期 XOR-RELAYED-ADDRESS=192.0.2.15:50000 :给client分配的relay地址 XOR-MAPPED-ADDRESS=192.0.2.1:7000 :client的经NAT后的映射地址 MESSAGE-INTEGRITY=... :一些加密信息

(5)收到TURN server的success响应后,client发送CreatePermission request来创建peer的权限。 Transaction-Id=0xE5913A8F460956CA277D3319 :另起一个事务,标识另外一个请求过程 XOR-PEER-ADDRESS=192.0.2.150:0 :需要创建权限的peer的IP地址,权限只与IP地址相关,与端口无关 USERNAME="George" REALM="example.com" :(2)中TURN server响应给client的 NONCE="adl7W7PeDU4hKE72jdaQvbAMcr6h39sm" :(2)中TURN server响应给client的 MESSAGE-INTEGRITY=... :一些加密的信息

(6)TURN server接受创建权限请求,发送CreatePermission success resp 响应给client Transaction-Id=0xE5913A8F460956CA277D3319 :事务ID要和(5)相同 MESSAGE-INTEGRITY=... :一些加密信息

(7)创建权限成功后,client就可以用Send indication来发送数据给TURN server然后由TURN server将数据relay给peer Transaction-Id=0x1278E9ACA2711637EF7D3328 :另起一个事务,标识另外一个请求过程 XOR-PEER-ADDRESS=192.0.2.150:32102 :需要发送数据的peer监听的IP:PORT(注意IP一定要和注册权限的时候的IP一样,否则会被拒绝relay并响应错误) DONT-FRAGMENT :请求TURN server不要将data数据分片发送 DATA=... :client需要发给peer的数据内容

(8)TURN server收到Send indication请求后,进行一些权限检查后,提取出协议包中的data属性中的数据内容,然后将数据内容用UDP协议从client的relay地址(源:192.0.2.15:50000)发送给peer(目的:192.0.2.150:32102) -- UDP dgm -> data=... : 发给peer的UDP 数据包

(9)peer收到UPD数据包后,如果有响应数据,那么就将响应数据用UDP发给TURN server的192.0.2.15:50000地址 <- UDP dgm – data=... :响应给TURN server的UDP数据包

(10)TURN server在client的relay地址(192.0.2.15:50000)那收到peer(192.0.2.150:32102)的UDP数据包,这时TURN server需要检测client是否注册了IP192.0.2.150的权限,如果没有就会丢弃该数据包。如果有那么就取出UDP数据包中的data部分,然后将data封装成TURN协议数据包,给client发送Data indication。 Transaction-Id=0x8231AE8F9242DA9FF287FEFF :协议并不要求这个事务ID要和(7)中的一样 XOR-PEER-ADDRESS=192.0.2.150:32102 :标识数据来自哪个peer DATA=... :peer 发给client的数据内容 以上是Send and Data methods方式的核心交互过程,较为完整交互过程可以查看一下协议文档。这里有个问题需要说明一下,就是每个allocation都有一个有效期,client需要把握好有效期,及时在有效期内发送refresh request来刷新延长有效期。

3.4.1.2 方式二、channels,具体交互过程如下:

(1)--(6)交互过程和Send and Data methods方式是一样的,这里就不在重复了。

(7)权限创建成功后,client发送ChannelBind request给TURN server请求进行channel bind。 Transaction-Id=0x6490D3BC175AFF3D84513212 :事务ID CHANNEL-NUMBER=0x4000 :client定义的bind channel ID XOR-PEER-ADDRESS=192.0.2.210:49191 :peer B的IP和PORT USERNAME="George" :同方式一 REALM="example.com" :同方式一 NONCE="adl7W7PeDU4hKE72jdaQvbAMcr6h39sm" :同方式一 MESSAGE-INTEGRITY=... :同方式一

(8)TURN server接受channelBind请求后,给client发送ChannelBind success response响应 Transaction-Id=0x6490D3BC175AFF3D84513212 :事务ID,和(7)相同 MESSAGE-INTEGRITY=... |

(9)client收到ChannelBind success response后就可以通过ChannelData来发送数据了。 Channel-number=0x4000 :(7)中定义bind channel ID Data=... :client需要发给peer B的数据内容

(10)TURN server收到ChannelData后首先从TURN协议数据包中提取出Channel-number,接着查找Channel-number是否已经绑定peer,如果没有就返回错误并丢弃数据包;如果查找到有绑定peer,那么就提前出Data属性中的数据内容用UDP协议通过client的relay地址(源:192.0.2.15:50000)发送给peer B(目的:192.0.2.210:49191)。 --- UDP datagram ---------> Data=... 发给peer B的UDP 数据包

(11)peer收到UPD数据包后,如果有响应数据,那么就将响应数据用UDP发给TURN server的192.0.2.15:50000地址 <-- UDP datagram ---------- Data=... :peer 发给client的数据内容

(12)TURN server在client的relay地址(192.0.2.15:50000)那收到peer(192.0.2.210:49191)的UDP数据包,这时TURN server需要检测client是否注册了IP192.0.2.150的权限,如果没有就会丢弃该数据包。如果有注册权限,那就检查client是有channel绑定该peer,如果有那么就通过Channel Data 方式relay数据给client,否则就通过方式一中的Data indication 方式relay数据给client Channel-number=0x4000 :(7)中定义bind channel ID Data=... :peer B发给client的数据内容

以上是channels的核心交互过程,较为详细的过程可以查看协议文档。方式二比方式一多了一个channel Bind的步骤,这个步骤是为了告诉TURN server接下来以Channel-number标识的协议数据包是要发给谁的,这样才使得ChannelData中只要携带一个Channel-number头部信息就可以,而不用携带方式一中的Transaction-Id、XOR-PEER-ADDRESS等额外的头部信息,减少数据量。

3.4.2 TCP协议的Relay

TCP协议的relay是在RFC6062中描述,其中主要有两种情况下的relay:1. Client to peer 2. Client to client。下面分别介绍两种情况下relay。

3.4.2.1 情况一、Client to peer,网络拓扑如下:

在上面的网络拓扑下,有两种方式的relay:1. TURN Client 主动发起的relay 2. TURN Peer主动发起的relay。下面分别介绍这两种方式的交互过程。这里Turn Client表示能够理解TURN协议的主机,而Turn Peer表示普通的一般主机。

3.4.2.1.1 TURN Client 主动发起的relay:

在这种方式下,TURN server要能够直接连接上TURN Peer监听的端口才行。具体交互过程如下:

(1)--(6)交互过程和RFC5766的是基本一样的,这里就不在重复了。所不同的是RFC5766中是UDP协议,而这里是TCP协议,并且(1)--(6)是在一个连接中完成,我们称这个连接为control connection。

(7)client创建权限成功后,通过control connection发送Connect request给TURN server请求TURN server去连接Peer A Transaction-Id=0x6490D3BC175AFF3D84513212 :事务ID XOR-PEER-ADDRESS=192.0.2.210:49191 :Peer A监听的IP和端口

(8)TURN server收到Connect request后, 它会通过client的relay地址(源:192.0.2.15:50000)尝试TCP连接到Peer A的192.0.2.210:49191,如果连接不成功,那么给client响应错误码为447的错误。如果连接成功那么转入(9),我们称这个连接为Peer data connection

(9)TURN server连接Peer A成功后,给client发送Connect success response Transaction-Id=0x6490D3BC175AFF3D84513212 :事务ID,同(7) CONNECTION-ID=0x123456787 :TURN server给client响应的标识,用于将两条TCP连接联系起来用的。

(10)client在control connection上收到Connect success response,那么client需要建立另外一条TCP连接连上TURN server,我们称这条连接为new connection。Client通过new connection给TURN server发送ConnectionBind request,请求将new connection和Peer data connection进行绑定。 Transaction-Id=0x6490D3BC175AFF3D84513212 :事务ID CONNECTION-ID=0x123456787 :(9)中收到的CONNECTION-ID (11)TURN server 收到ConnectionBind request后,进行一些操作,把new connection和Peer A connection两条TCP连接联系起来。

通过上面11个步骤以后,client和peer A就能分别通过new connection和Peer data connection两条TCP连接来发送数据了。Client通过new connection发送的数据到达TURN server,TURN server就会将数据原封不动通过Peer data connection转发给Peer A,同样对于Peer A也是一样的,TURN server就像进行端口转发一样了。这里有个问题是:Peer A connection这条TCP连接要比new connection这条TCP连接早一些建立起来的,这样在new connection建立起来之前peer A就开始发送数据的话,那么TURN server这个时候是无法将数据转发给client的,所以RFC6062协议要求,只要Peer data connection连接建立好了,那么TURN server就必须做好准备接收peer A的数据,并将接收到的数据buffer住,等new connection建立好后在转发给client。但是,有些开源实现并没有这样做,所以这点要注意一下。

3.4.2.1.2 TURN Peer主动发起的relay

在这种方式下,TURN Peer可以位于NAT后面,具体交互如下:

(1)--(6)交互过程和方式1的是一样的,这里就不在重复了。

(7)Peer A通过192.0.2.210:49191向client的relay地址192.0.2.15:50000发起TCP连接。TURN server 马上accept这个TCP连接并做好buffer Peer A发送的数据流的准备。然后,TURN server检查 拥有relay地址192.0.2.15:50000的client是否已经注册了Peer A(192.0.2.210)的权限,如果没有,那么TURN server会马上close刚刚accept的连接。如果有,那么转向(8),我们把这个连接称为peer data connection

(8)TURN server 查找到拥有relay地址192.0.2.15:50000的client的control connection,通过control connection给client发送ConnectionAttempt indication。 Transaction-Id=0x6490D3BC175AFF3D84513212 :事务ID XOR-PEER-ADDRESS=192.0.2.210:49191 :(7)中accept那个peer A的IP和端口 CONNECTION-ID=0x789465213545 :TURN server给client响应的标识,用于将两条TCP连接联系起来用的

(9)client收到ConnectionAttempt indication,如果接收这个peer的话,那么client会新起一个连接连上TURN server,我们称这个连接为new connection,client通过new connection给TURN server发送ConnectionBind request,请求绑定peer data connection。 Transaction-Id=0x6490D3BC175AFF3D84513212 :事务ID CONNECTION-ID=0x789465213545 : (8)中收到的CONNECTION-ID

(10)TURN server收到ConnectionBind request后会通过new connection给client发送ConnectionBind request success response。

通过上面10个步骤以后,client和peer A就能分别通过new connection和Peer data connection两条TCP连接来发送数据了。这个方式同样存在方式1中的数据buffer住问题。在这种情况下,在Peer A看来与之通信的是Endpoint(client的relay地址192.0.2.15:50000),Peer A不需要知道真实的Client的地址。

3.4.2.2 情况二、Client to client,网络拓扑结构如下:

这种情况下,RFC6062文档中并没有讲到,估计是因为这种情况是情况一的一个特例而已,我这里展开来讲一下是希望能帮助大家更加深刻理解协议本身。 TURN Client1和TURN Client2(1)-(6)步骤的交互情况基本和上面的一样,并且是比较独立的,所以下面直接给出了。 TURN Client1 的(1)-(6)步骤交互情况如下:

TURN Client2 的(1)-(6)步骤交互情况如下:

从上面的交互可以知道TURN Client 1 的relay地址是:192.0.2.15:50000 ,NAT映射后的地址是:192.0.2.1:7000,而TURN Client2的relay地址是:192.0.2.150:40000 ,NAT映射后的地址是:192.0.2.2:7000。下面继续给出TURN Client 1和TURN Client 2的其他交互情况,由于它们和TURN server的交互带有一定的时序性,下面会交错给出它们和TURN server的交互步骤。TURN Client1和TURN Client2是对称,这里不妨假设TURN Client1是数据交互的发起者,具体交互过程如下:

(7)TURN Client1 首先通过control connection1发送Connect request给TURN server,请求连接TURN Client 2的relay地址192.0.2.150:40000。 Transaction-Id=0x6490D3BC175AFF3D84513212 :事务ID XOR-PEER-ADDRESS=192.0.2.150:40000 : TURN Client2的relay地址

(8)TURN server收到Connect request后, 它会通过TURN Client1的relay地址(源:192.0.2.15:50000)尝试TCP连接到192.0.2.150:40000,这个连接一般都会成功,因为这个是TURN server给的relay地址,我们称这个连接为peer data connection1

(9)TURN server连接192.0.2.150:40000成功后,给TURN Client1发送Connect success response Transaction-Id=0x6490D3BC175AFF3D84513212:事务ID CONNECTION-ID=0x123456787 :TURN server给client响应的标识,用于将两条TCP连接联系起来用的

(10)这个步骤和(9)几乎同时发生的,TURN server发现TURN Client2的relay地址192.0.2.150:40000有个TCP连接上来,那么TURN server马上accept这个连接,我们称这个连接是peer data connection2(其实就是peer data connection1);经过权限检查后,TURN server通过TURN Client2的control connection2给TURN Client2发送ConnectionAttempt indication Transaction-Id=0x6490D3BC175AFF3D84511111 :事务ID XOR-PEER-ADDRESS=192.0.2.15:50000 :TURN Client1的relay地址 CONNECTION-ID=0x789465213545 :TURN server给client响应的标识,用于将两条TCP连接联系起来用的

(11)TURN Client1 收到Connect success response后,另起一个TCP connection连接上TURN server,我们称这个连接为new connection1。TURN Client1通过new connection1给TURN server 发送ConnectionBind request Transaction-Id=0x6490D3BC175AFF3D84513212 :事务ID CONNECTION-ID=0x123456787 : (9)中TURN server响应的CONNECTION-ID

(12)这个步骤几乎和(11)同时发生,TURN Client2 收到ConnectionAttempt indication,表示接受,然后它另起一个TCP connection连接上TURN server我们称这个连接为new connection2。TURN Client2通过new connection2给TURN server发送ConnectionBind request。 Transaction-Id=0x6490D3BC175AFF3D84511111 :事务ID CONNECTION-ID=0x789465213545 :(10)中TURN server响应的CONNECTION-ID

(13)和(14)TURN server分别通过new connection1和new connection2给TURN Client 1和TURN Client 2发送ConnectionBind request success response。

通过以上14个步骤,TURN Client 1就能借助new connection1和peer data connection1与TURN Client 2进行数据交互。而TURN Client 2借助new connection2和peer data connection2与TURN Client 1进行数据交互。

到这里,P2P通信穿越NAT的相关原理、技术、方法基本介绍完毕,关于STUN和TURN协议,有个开源实现,有兴趣的同学可以阅读一下源码:https://github.com/coturn/rfc5766-turn-server

另外还有一个ICE协议,这个也有一个文档系列:这个文档系列较为复杂一些,有兴趣的可以阅读一下。 RFC 5245 - ICE RFC 5768 – ICE–SIP RFC 6336 – ICE–IANA Registry RFC 6544 – ICE–TCP RFC 5928 - TURN Resolution Mechanism

4 . 参考文献

[1] NAT概述 [2] Peer-to-Peer Communication Across Network Address Translators

原创声明,本文系作者授权云+社区-专栏发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏码神联盟

JAVA架构 | Redis分布式缓存原理分析

1引言 Redis是Remote Dictionary Server(Redis) 的缩写,或许光听名字你就能猜出它大概是做什么的。不错,它是一个由Salvat...

3515
来自专栏SDNLAB

数据中心内的负载均衡-MPTCP

以手机为例,手机包含两种上网方式,蜂窝移动数据网络(2G,3G,4G)和WIFI网络。我们希望在有WIFI的时候尽量使用WIFI,这样可以节省成本,没有WIFI...

713
来自专栏Java架构沉思录

互联网是如何形成的

全世界几十亿台电脑,连接在一起,两两通信。上海的某一块网卡送出信号,洛杉矶的另一块网卡居然就收到了,两者实际上根本不知道对方的物理位置,你不觉得这是很神奇的事情...

1053
来自专栏Linux驱动

IIC接口下的24C02 驱动分析

本节来学习IIC接口下的24C02 驱动分析,本节学完后,再来学习Linux下如何使用IIC操作24C02 1.I2C通信介绍 它是由数据线SDA和时钟SCL构...

1889
来自专栏玄魂工作室

Web应用系统介绍-TCP/IP协议

大家先冷静一下上了一天班的大脑先~~~ 然后我们再讲理论~ 以下内容非常枯燥,但是也是非常有用~ 在我们开始CTF的道路之前,希望你们能知道并理解下面基本概念...

3134
来自专栏Web项目聚集地

互联网是怎么形成的?

全世界几十亿台电脑,连接在一起,两两通信。上海的某一块网卡送出信号,洛杉矶的另一块网卡居然就收到了,两者实际上根本不知道对方的物理位置,你不觉得这是很神奇的事情...

831
来自专栏趣谈编程

互联网协议入门(上)

全世界几十亿台电脑,连接在一起,两两通信。上海的某一块网卡送出信号,洛杉矶的另一块网卡居然就收到了,两者实际上根本不知道对方的物理位置,你不觉得这是很神奇的事情...

840
来自专栏java思维导图

互联网协议入门(一)

技术文章第一时间送达! 本文来自“阮一峰的网络日志”,欢迎点击阅读原文 我们每天使用互联网,你是否想过,它是如何实现的? 全世界几十亿台电脑,连接在一起,两两通...

2576
来自专栏张善友的专栏

zookeeper 分布式锁服务

分布式锁服务在大家的项目中或许用的不多,因为大家都把排他放在数据库那一层来挡。当大量的行锁、表锁、事务充斥着数据库的时候。一般web应用很多的瓶颈都在数据库上,...

1888
来自专栏编程思想之路

BLE低功耗蓝牙开发相关概念问题记录

蓝牙ble的传输速率是指主从机每秒所传输的字节数。既然是传输速率那就涉及到时间和每次所传递包大小的问题。 关于ble通信的demo可以参考蓝牙API介绍及基...

2196

扫码关注云+社区