原来这是由于IPV4引发的,咱们上网极可能会处在一个NAT设备(无线路由器之类)以后。
NAT设备会在IP封包经过设备时修改源/目的IP地址. 对于家用路由器来讲, 使用的是网络地址端口转换(NAPT), 它不只改IP, 还修改TCP和UDP协议的端口号, 这样就能让内网中的设备共用同一个外网IP. 举个例子, NAPT维护一个相似下表的NAT表:安全
NAT设备会根据NAT表对出去和进来的数据作修改, 好比将192.168.0.3:8888
发出去的封包改为120.132.92.21:9202
, 外部就认为他们是在和120.132.92.21:9202
通讯. 同时NAT设备会将120.132.92.21:9202
收到的封包的IP和端口改为192.168.0.3:8888
, 再发给内网的主机, 这样内部和外部就能双向通讯了, 但若是其中192.168.0.3:8888
== 120.132.92.21:9202
这一映射由于某些缘由被NAT设备淘汰了, 那么外部设备就没法直接与192.168.0.3:8888
通讯了。服务器
咱们的设备常常是处在NAT设备的后面, 好比在大学里的校园网, 查一下本身分配到的IP, 实际上是内网IP, 代表咱们在NAT设备后面, 若是咱们在寝室再接个路由器, 那么咱们发出的数据包会多通过一次NAT.网络
国内移动无线网络运营商在链路上一段时间内没有数据通信后, 会淘汰NAT表中的对应项, 形成链路中断。架构
而国内的运营商通常NAT超时的时间为5分钟,因此一般咱们TCP长链接的心跳设置的时间间隔为3-5分钟。**rest
NAT会有一个机制,全部外界对内网的请求,到达NAT的时候,都会被NAT所丢弃,这样若是咱们处于一个NAT设备后面,咱们将没法获得任何外界的数据。code
可是这种机制有一个解决方案:就是若是咱们A主动往B发送一条信息,这样A就在本身的NAT上打了一个B的洞。这样A的这条消息到达B的NAT的时候,虽然被丢掉了,可是若是B这个时候在给A发信息,到达A的NAT的时候,就能够从A以前打的那个洞中,发送给到A手上了。orm
简单来说,就是若是A和B要进行通讯,那么得事先A发一条信息给B,B发一条信息给A。这样提早在各自的NAT上打了对方的洞,这样下一次A和B之间就能够进行通讯了。路由
RFC3489 中将 NAT 的实现分为四大类:io
Full Cone NAT (彻底锥形 NAT)form
Restricted Cone NAT (限制锥形 NAT ,能够理解为 IP 限制,Port不限制)
Port Restricted Cone NAT (端口限制锥形 NAT,IP+Port 限制)
Symmetric NAT (对称 NAT)
其中彻底最上层的彻底锥形NAT的穿透性最好,而最下层的对称形NAT的安全性最高。
简单来说讲这4种类型的NAT表明什么:
至于为何没法协调打洞,下面咱们会从STUN和TURN的工做原理来说。
完成了这些STUN Server就会这些基本信息发送回客户端,而后根据NAT类型,来判断是否须要TURN服务器协调进行下一步工做。
咱们来说讲这两步具体作了什么吧:
第一件事就不用说了,其实就是获得客户端的请求,把源IP和Port拿到,添加到ICE Candidate中。
假设B是客户端,C是STUN服务器,C有两个IP分别为IP1和IP2(至于为何要两个IP,接着往下看):
B向C的IP1的pot1端口发送一个UDP 包。C收到这个包后,会把它收到包的源IP和port写到UDP包中,而后把此包经过IP1和port1发还给B。这个IP和port也就是NAT的外网 IP和port(若是你不理解,那么请你去看个人BLOG里面的NAT的原理和分类),也就是说你在STEP1中就获得了NAT的外网IP。
熟悉NAT工做原理的朋友能够知道,C返回给B的这个UDP包B必定收到。若是在你的应用中,向一个STUN服务器发送数据包后,你没有收到STUN的任何回应包,那只有两种可能:一、STUN服务器不存在,或者你弄错了port。二、你的NAT拒绝一切UDP包从外部向内部经过。
当B收到此UDP后,把此UDP中的IP和本身的IP作比较,若是是同样的,就说明本身是在公网,下步NAT将去探测防火墙类型,我不想多说。若是不同,说明有NAT的存在,系统进行STEP2的操做。
B向C的IP1发送一个UDP包,请求C经过另一个IP2和PORT(不一样与SETP1的IP1)向B返回一个UDP数据包(如今知道为何C要有两个IP了吧,虽然还不理解为何,呵呵)。
咱们来分析一下,若是B收到了这个数据包,那说明什么?说明NAT来着不拒,不对数据包进行任何过滤,这也就是STUN标准中的full cone NAT。遗憾的是,Full Cone Nat太少了,这也意味着你能收到这个数据包的可能性不大。若是没收到,那么系统进行STEP3的操做。
B向C的IP2的port2发送一个数据包,C收到数据包后,把它收到包的源IP和port写到UDP包中,而后经过本身的IP2和port2把此包发还给B。
和step1同样,B确定能收到这个回应UDP包。此包中的port是咱们最关心的数据,下面咱们来分析:
若是这个port和step1中的port同样,那么能够确定这个NAT是个CONE NAT,不然是对称NAT。道理很简单:根据对称NAT的规则,当目的地址的IP和port有任何一个改变,那么NAT都会从新分配一个port使用,而在step3中,和step1对应,咱们改变了IP和port。所以,若是是对称NAT,那这两个port确定是不一样的。
若是在你的应用中,到此步的时候PORT是不一样的,那么这个它就是处在一个对称NAT下了。若是相同,那么只剩下了restrict cone 和port restrict cone。系统用step4探测是是那一种。
B向C的IP2的一个端口PD发送一个数据请求包,要求C用IP2和不一样于PD的port返回一个数据包给B。
咱们来分析结果:若是B收到了,那也就意味着只要IP相同,即便port不一样,NAT也容许UDP包经过。显然这是Restrict Cone NAT。若是没收到,没别的好说,Port Restrict NAT.
这4步都会返回给客户端它的公网IP、Port和NAT类型,除此以外:
若是A处于公网或者Full Cone Nat下,STUN不作其余的了,由于其余客户端能够直接和A进行通讯。
若是A处于Restrict Cone或者Port Restrict NAT下,STUN还会协调TURN进行NAT打洞。
若是A处于对称NAT下,那么点对点链接下,NAT是没法进行打洞的。因此为了通讯,只能采起最后的手段了,就是转成C/S架构了,STUN会协调TURN进行消息转发。
若是A和B要互相通讯,那么TURN Server,会命令A和B互相发一条信息,这样各自的NAT就留下了对方的洞,下次他们就能够之间进行通讯了。
当A或者B其中一方是对称NAT时,那么给这一方发信息,就只能经过TURN Server来转发了。
假如A、B进行通讯,而B处于对称NAT之下,那么A与B通讯,STUN拿到A,B的公网地址和端口号都为10000,而后去协调TURN打洞,那么TURN去命令A发信息给B,则A就在NAT打了个B的洞,可是这个B的洞是端口号为10000的洞,可是下次B若是给A发信息,由于B是对称NAT,它给每一个新的IP发送信息时,都从新对应一个公网端口,因此给A发送请求多是公网10001端口,可是A只有B的10000端口被打洞过,因此B的请求就被丢弃了。
显然Server是没法协调客户端打洞的,由于协调客户端打得洞仅仅是上次对端为Server发送端口的洞,并不适用于另外一个请求。