打洞这原理也不是我起码不是CSDN中任何一个人所创的,这个原理应该来网关(路由器NAT)的制造者,首先不请自来的数据NAT会毫不客气的丢掉的,这大家都认可,然后就是那套打洞逻辑了:
我们先看下图:
在Client A和Client B之间建立UDP直连的过程如下:
(1) Client A登录Server S,NAT A 为这次的Section分配了一个端口55000,那么Server S收到Client A的地址是100.10.10.10:55000,这就是Client A的外网地址。
(2)Client B登录 Server S, NAT B 给此次Section分配的端口是44000,那么Server S收到B的地址是:200.20.20.20:44000。
此时,Client A 与Client B 都可以与Server S通信了。如果此时Client A想直接发送UDP数据包给Client B,那么 Client A可以从Server S 中获得B的公网地址:200.20.20.20:44000,但是Client A还不能使用该公网地址直接和Client B通信,因为此时NAT B会将Client A主动发来的信息丢弃,因为此数据包是没有会话记录的。
(3)现在需要在NAT B上打一个方向为100.10.10.10:55000(即Client A的外网地址)的洞,那么Client A发送到200.20.20.20:44000的信息,Client B就能收到了。
(4)Server S负责向Client B发送打洞指令。
(5)Client B向Client A的公网地址发送一个UDP报文,虽然此时数据包会被NAT A丢弃,但是在NAT B上建立了会话记录,不会丢弃Client A的包了。
(6)Server S通知Client A "洞"已打好,Client A可以发数据包给Client B了。
(7)Client A向Client B发送UDP包。
(8) 至此双方可以进行UDP通信了。
注意:
以上过程仅适合Cone NAT的情况,如果是对称的NAT,那么当Client B向Client A发送报文时,Client A的打洞端口已经从新分配了,Client B将无法得知,这个时候可以用一个端口猜测算法(该算法不适用全部,但大部分适用)。
还有一点,网络通信是很复杂的,UDP数据包容易丢包,所以发数据时要多发几次,而且是连续的发,因为打洞的UDP端口是有生命周期的,这个周期有时候很短,所以有些同学打不通,或者一时通一时不通,于是就搞不明白什么原因,还有要会反过来打,尤其是TCP,正打有时候不通,反过来就通了。
TCP打洞跟这个类似,但真正实现起来是不一样的,我相信我这里描述的跟网上很多人描述的都大同小异,其实说实话,大部分人提供的源码都只是玩具而已,不能用的,TCP打洞较成功的例子我看看了,就数XSTUNT了,其他的也许没发现。
打洞是需要多机器来测试的,尤其是TCP,”同步协调“,”多次“ ”循环“ 这几个词挂耳边,不经过具体大型系统实践的人说出来都是空话,我们的系统TCP穿透基本参考XSTUNT实现,效果还可以,所以我也不需要多做太多额外的工作,就写这么多,
后面还要总结KAD 的东西。