UDP打洞和为何打洞、为什么TCP”不适合”P2P,以及NAT介绍(下面讲的是NAT的NAPT) 您所在的位置:网站首页 rustdesktop UDP打洞和为何打洞、为什么TCP”不适合”P2P,以及NAT介绍(下面讲的是NAT的NAPT)

UDP打洞和为何打洞、为什么TCP”不适合”P2P,以及NAT介绍(下面讲的是NAT的NAPT)

2023-03-27 14:00| 来源: 网络整理| 查看: 265

UDP打洞和为何打洞、为什么TCP"不适合"P2P,以及NAT介绍(下面讲的是NAT的NAPT)

下面介绍流程如下

A、NAT中的4种NAPT B、NAT的概念 为什么会出现NAT NAT是啥,能干啥 C、TCP是否需要NAT,以及谈谈为什么UDP需要打洞(什么是NAT穿透) TCP当然也是需要走上面的NAT流程的 TCP是否能实现P2P TCP有链接和UDP无连接 为什么需要UDP打洞(什么是UDP打洞/NAT穿透) D、如何实现UDP打洞(NAT穿透),实现流程。

A、先简单介绍NAT中的4种NAPT类型

? 对称NAT进行打洞/穿透比较随缘(家用路由据说一般都不是对称NAT,即是锥形的)。

全锥型(Full Cone)

受限锥型(Restricted Cone) 限制IP

端口受限锥型(Port Restricted Cone) 限制IP和PORT

对称型(Symmetric) 限制IP和PORT,并且不同外网和内部使用NAT的不同PORT

对称和锥型最大的区别就是是否NAT使用同一个端口了。

B、谈论打洞问题之前,必须先了解NAT概念。

为什么会出现NAT。

学过计网的都知道ACBDE类IP地址吧,IPv4地址总共就32位,地球上上网的那么多,每个人都分一个的话肯定不够(IPv6就不说了,毕竟还没有做到全普及)。为了解决这个ipv4地址不够所有人用的问题,就诞生了NAT。

NAT是啥,能干啥。

? NAT是一种网络地址转换方法,用一个port标识内网和外网的联系。

? 前面提到IPv4的地址是有限的,生活中拥有IPv4公网地址的往往是网络提供商(联通、电信、移动之类的)。我们为了能"上网"(连接互联网的意思),那么肯定需要一个IPv4公网地址,这样别人才能在网络上找到我,我也才能找到别人(指拥有IPv4公网地址的人)。网络提供商肯定不能直接让你用这个IPv4标识你自己的电脑,为什么呢?因为要是你这么干,别人也会这么干。假如2个人甲和乙都能共用这个ipv4(1.1.1.1)。那么甲(1.1.1.1:80)和另一个网友老王(ipv4:2.2.2.2:80)聊天,结果老王回复你的时候,乙(ipv4:1.1.1.1:80)收到了这个消息,那不是乱套了。

? 网络提供商(拥有ipv4:1.1.1.1的机器)开辟了一个WAN广域网,甲和乙都去找它办宽带了,甲宽带分配到ip(162.100.100.1),乙分配到ip(168.240.162.5),这两个ip是联系ipv4:1.1.1.1用的,不能直接和互联网上的ipv4交流。

? 有了各自的宽带后,甲就能够和老王聊天了。但是甲的ip162.100.100.1不是ipv4,不处于互联网,不能和老王直接交流。这时候NAT就出来帮忙了。甲(162.100.100.1:80)–NAT(网络提供商ipv4:1.1.1.1:6751)–>老王(ipv4:2.2.2.2:80)。

? NAT使用一个port标识 甲的ip:port(162.100.100.1:80)和另一个外网ipv4拥有者老王(ipv4:2.2.2.2:80)的联系。

? 老王收到甲的消息时,看到的ip和port只能是公网ipv4的,也就是网络提供商ipv4:1.1.1.1:6751。老王给甲回消息,也是传给ipv4:1.1.1.1:6751。这里老王根本不知道甲处在的WAN中的ip和port到底是多少。

? 网络提供商的路由器查找NAT表,得知6751端口标识的是自己创建其中一个WAN中的甲和老王的联系。于是把ipv4:1.1.1.1:6751收到的数据发送给甲(162.100.100.1:80)。

? 这样一来甲和老王就成功联系在一起了。甲----甲处在的网络的NAT—> 老王;老王----甲处在的网络的NAT---->甲。

? 这里需要说明几个重要的知识点,为了下面提到UDP打洞做铺垫。

一,那就是NAT映射必须由该WAN内的用户建立。换句话说就是,在甲主动联系老王之前,老王是不可能知道怎么联系甲的,就算甲把自己的ip和端口(162.100.100.1:80)告诉了老王也没有用,因为甲的这个ip只有在甲所处的WAN网络内才是有效的。只有甲主动联系老王后,NAT表上才会多一个端口port记录这条"通道",老王也才能通过这个"通道"访问到甲。

二,NAT4种模式对于NAT的映射处理不同,基本是出于安全的考量。

三,NAT标记内网和外网交流的端口port不是永久分配的,会有回收时间的。

? 这个很好理解,不然你要是程序都不运行了,还占用网络提供商路由器的端口6751,你一个人还好,要是一堆人都这么干,明明不上网了却还占用NAT表的port,久而久之NAT表爆满了,每个port都被用掉了,那么大家都别想用到这个ipv4(1.1.1.1)了,都不用上网了。

C、在大致了解了NAT后,聊聊TCP是否需要NAT,以及谈谈为什么UDP需要打洞(什么是NAT穿透)

TCP当然也是需要走上面的NAT流程的!

? 只要甲想要和老王聊天,那就必须用ipv4,而甲只能通过NAT来获取ipv4和老王聊天。这里甲和老王聊天如果使用到的是TCP,那么往往是 甲–甲to老王的聊天信息–> 聊天TCP服务器 --甲to老王的聊天信息–>老王。

? 聊天软件作为中介一般的存在,和甲、老王分别连接TCP连接,然后之后分别使用channel通道和甲、老王交流数据(这里channel实际上不是同一个,但是逻辑上就像是同一个,下面直接用一个标识)交流。

? 甲–channel+A–聊天服务器–channel+B–老王(他其实也是在另一个WAN里面,用的也是网络提供商的ipv4)

? 建立连接后,为了保持这个channel的有效性,甲会每隔一段时间发心跳包给聊天服务器,老王同理。这样子甲和老王各自所处的WAN的NAT表就会一直保持甲、老王各自和聊天服务器的联系,使用port标记。

? 对于TCP开发来说,如果长时间没有发送心跳包,tcp连接就会断开(其实就是NAT上面的port失效了,联系外网失败了,据说NAT标记port时,对于TCP的保留会比UDP久,我自己没实际测试过具体差异)。

UDP为什么需要打洞。讲之前先讲讲TCP是否能实现P2P。

? UDP通信的开发不像TCP有连接通信,TCP这种有连接的模式,往往是A-B-C三者之间。比如上面的甲–聊天服务器–老王。聊天服务器为了能让甲和老王聊天,必须一直记录甲和老王各自的NAT拥有的ipv4和记录port。UDP主要还可以用在P2P聊天模式(直接 甲—老王,不过首先还是得至少经过一次甲–聊天服务器–老王)。

? 这里先讨论下TCP能不能实现P2P聊天。P2P也就是甲和老王交流完全不通过第三方,甲信息直接第一手交给老王,老王同理。不是所有情况TCP都可以实现P2P(这和TCP需要建立连接有关)。

? 只有在甲和老王都是直接拥有ipv4的情况下,可以通过直接TCP实现P2P。

甲和老王都是直接拥有ipv4的用户。

? 这种情况没啥好说的,甲和老王能够直接通过ipv4建立TCP连接了,不需要通过任何转换和中介,也就是P2P了。

甲或者老王仅有其中一方拥有ipv4(假设老王有ipv4)

? 这种情况下,甲要和老王交流必须通过NAT。老王向甲发话,实际上是向甲所在的NAT(1.1.1.1:6751)发话。由于前面提到NAT必须由内网用户主动发起,外网才能发现这个WAN的NAT的ip和port,所以老王是不可能直接向甲发话的,必须甲先主动和老王发话,老王才能找到甲。

? 这种情况TCP如果要老王和甲建立连接且P2P交流,那么必须老王能够知道甲所在的WAN对应的NAT的ip和port。但是老王是不可能知道甲所在的NAT的port的,这个必须甲先发出请求后,老王才能获取到port,而且老王并无法确定这个port一定是对应甲的。因为甲所在的WAN中不止甲能够使用NAT和老王交流,完全可以冒出来一个乙也故意发相同内容的数据包给老王。老王收到2个数据包,ip都是(1.1.1.1),但是一个port是(6571甲),另一个是(6682乙),由于数据包的内容完全一模一样,请问老王要记住哪个port来建立TCP连接?正是由于这种原因,TCP就算这种情况能实现P2P,也不安全。

甲和老王都没有ipv4,都是通过各自的NAT来使用网络提供商的ipv4进行互联网交流

? 这种情况甲和老王甚至完全没办法直接交流(指不通过第三方公网ipv4)。原因如下,甲不知道老王的网络提供商ipv4是多少,老王也不知道甲的网络提供商ipv4是多少。就算甲和老王各自上网查了自己的网络提供商的ipv4分别是(1.1.1.1)和(2.2.2.2),甲和老王还是不能互相交流。

? 原因很简单,前面提过了NAT必须由一方先发起。这里甲和老王谁发起都一样。假设甲知道老王的WAN的ipv4是2.2.2.2,于是他通过162.100.100.1:80打算通过自己的WAN的1.1.1.1向2.2.2.2发包,然后他意识到根本不知道向2.2.2.2的哪个端口发包。因为NAT的port必须内网的那方先向外网发送后才会分配。

? 所以这种情况直接P2P是百分百不可能的。必须有像聊天服务器这类拥有ipv4的存在作为中介存储甲和老王各自的NAT的ipv4和port,甲和老王才能够交流。

上面对TCP是否能够建立P2P进行了一定的探讨。其实最主要的问题就是NAT影响了甲和老王之间是否能够直接联系。

? 下面回到UDP打洞问题之前,再讲讲TCP有链接和UDP无连接。

? UDP不像TCP需要建立连接(3次握手和4次挥手)。UDP只要知道发送的地址ip:port和自己的ip:port就ok了。TCP建立连接的好处就是建立连接后不需要关注网络状态变化。因为只要网络状态变化了,TCP就可以将其视为连接断开,那么下次A和B要交流时就重新记录ip和port。所以建立TCP连接的代价就是每次变换网络都需要重新建立连接(这个操作耗时,也会比UDP效率低),但是建立连接后的所有操作,都不需要考虑ip和port这些网络层的东西了。

? UDP相对TCP灵活,因为UDP不需要建立连接。换言之,UDP每次发送都要得知对方的ip和port。如果甲和老王都直接拥有ipv4,这时候使用UDP交流可以省去TCP的3次建立连接的操作。但是现实中,哪有那么理想的情况,往往是甲和老王的ip、port会一直变动。

? 现在假设我们聊天服务器用UDP实现,不用TCP。那么必然会面临一个问题:

甲和老王的ip和port时常变动,甲必须通过某种形式了解到老王最新的ip和port,才能和其进行p2p交流。

前面多次强调如果用到NAT,那么不通过第三方是不可能实现P2P的。这里也是一样的。我们的解决手段通常如下:

(1)甲—udp—> 拥有ipv4的服务器(记录甲所在的WAN的NAT的ip和port,这个port标记甲和服务器的联系,假设为1.1.1.1:6751)

(2)老王—udp—> 拥有ipv4的服务器(记录甲所在的WAN的NAT的ip和port,这个port标记老王和服务器的联系,假设为2.2.2.2:7891)

(3)甲想直接和老王进行p2p交流。于是服务器把2.2.2.2:7891发给甲,和甲说你发给这个地址就可以和老王进行交流了(对老王也进行相同操作),“以后别找我做中介了”(实际是不可能真的再也不找他做中介的,后面会说原因)。

(4)甲直接把数据包发到2.2.2.2:7891,结果被老王所在的WAN的NAT直接拒绝了。这个过程由于甲访问的目的地址不再是服务器,而是老王所在的WAN,所以甲的WAN的NAT对于这次操作的记录port不一定是原本的6751。(具体port会是多少,首先和NAT的类型有关,其次和服务提供商的NAT分配port的策略有关)

(5)老王不知道甲的数据包被拒绝这件事,在这之后的较短时间内也发了数据给甲的1.1.1.6751。(太长的话甲的WAN的NAT,1.1.1.1:6751就会去掉这个甲试图访问老王的这条记录,这里假设甲和老王之间的这个联系用的还是甲WAN的NAT的6751端口,同时假设老王访问甲的这次操作用的还是2.2.2.2:7891)

(6)“奇迹发生了”,甲获取到了老王的聊天信息,并且之后再发送一次给老王上次的信息,老王也收到了。

这里不知道大家还记不记得前面提到的NAT,必须由内网一方主动联系外网,NAT才会标记一个port标识这个联系。(这里出于两方都是全锥型(Full Cone) NAT的情况)

正是由于如此,甲第一次访问老王,由于老王没有主动联系过甲,该数据包被老王的NAT直接丢弃;

但是虽然甲的数据包被老王的NAT丢弃了,但是甲这个操作使得甲的NAT用port标记了这次行为;

老王在甲的NAT的port过期之前发送数据给甲,由于甲有事先尝试联系过老王,甲的NAT-port有记录,所以老王的数据包没有被丢失,被甲WAN的NAT转发给了老王;

之后同理,由于老王访问过甲,甲再次访问老王也就能访问得通了。

上面这种甲能够访问老王的操作,这是UDP打洞(NAT穿透)。

D、如何实现UDP打洞(NAT穿透)

? 大致了解TCP和UDP后。接下来就是UDP打洞来实现P2P了。但UDP实现的P2P,在用到NAT的情况下,其实还是不能完全的P2P的,中间还是得借助第三方。

? 通过前面大篇幅的介绍,得知甲如果想和老王通过UDP通信,需要时刻知道对方的最新ip和port。这需要有第三方记录两者的ip和port的更新(聊天服务器记录)。

? 下面假设甲和老王都是端口受限锥形NAT的前提下进行UDP打洞。因为如果两者都是对称NAT或者一个对称,一个端口受限锥形的话,虽然可以通过巧妙的算法实现P2P,但是消耗还是挺大的,复杂度也高。(直接说这2种情况就不能实现打洞也不是不行,因为实在复杂,依赖的条件还涉及网络提供商的NAT-port分配策略,条件算苛刻的)

打洞流程大致如下:

(1)甲—UDP—>聊天服务器(这个过程很频繁,假设50s一次,这个UDP包可以什么数据都没有,指记录甲WAN的NAT对应的ip和port)

(2)老王—UDP—>聊天服务器(同理50s一次,时间设置短一方面是防止NAT的port过期,一方面是能尽可能更上用户的ip、port变换速度。当然不是越短越好,没必要1s一次UDP,那用户流量不炸裂)

(3)当甲单方面和老王想要P2P私聊的时候,甲和服务器反应,服务器把甲想和老王私聊的事情告诉老王,并把服务器关于甲的地址记录(1.1.1.1:6751)发送给老王,同时也把老王的告诉甲,老王发送空数据的UDP给甲(当然被甲WAN的NAT丢弃了)。

? 老王—UDP—>甲。由于老王NAT是端口受限锥形NAT,老王访问甲的这个操作会使得老王WAN为其分配新的(port2.2.2.2:7777),之前的(port2.2.2.2:7891)是对应老王和服务器之间的联系。

(4)甲虽然没收到老王的包,但是因为甲单方面想和老王P2P私聊,所以是肯定会向老王(2.2.2.7891,服务器之前通知甲的是这个)发送聊天信息。同理甲WAN的NAT会新建port标识这一个操作(1.1.1.1.6666)。

? 聪明的你是不是发现问题了,那就是这样下去甲和乙都会陷入死循环,互相发包,阁制WAN的NAT一直重新分配port标识甲->老王或者老王->甲。(这里我没实际操作过,但从理论上推测,只要甲和老王WAN的NAT各自会舍弃对方的包且重新分配port,那么只要没有运气好某一方访问对面的时候port正好撞上了,那么就死循环)。

? 虽然网上说端口受限锥形NAT和端口受限锥形NAT两方也是可以UDP打洞的,但是我暂时从上面的推测,感觉也是行不通的。理由也很简单,因为NAT对内网用户来说是透明的,甲本身不知道自己对应的NAT的ip和port是多少,没法直接把变化后的甲WAN的NAT-ip-port告诉老王,同理也不可能先告诉服务器再转告给老王。(NAT可以静态配置,但是NAPT我不清楚有没有,如果也可以自己指定NAT的ip和port,那么就不会死循环)

? 当甲或者老王其中一方不是端口受限锥形NAT(限制IP和port),而是更为宽松的受限锥型NAT(只限制IP)时,再考虑上面打洞的(4)时,同理发现打洞没法进行。假设甲的NAT只限制IP,由于老王发送的数据包,甲的NAT是第一次看见这个IP和port,所以丢弃,进而甲永远没法知道和老王通信的ip和port。如果老王是只限制IP的NAT的那一方,那同理,甲的NAT还是舍弃了老王的包。和前面的双方都是端口受限锥形NAT一样,由于自身没法获取自己的NAT,所以没法和对方交流。

? 接下来考虑甲是全锥型NAT(不限IP和port,甲的该应用162.100.100.1:80和1.1.1.1交互永远使用的是port7891)。这种情况下,打洞的(4)就可以进行了。

(4)甲能收到老王的包,因为甲该应用对外使用的NAT-port一直都是7891。甲获取到老王WAN的NAT新分配给老王的2.2.2.2:7777,并且直接通过该ip和port向老王发送消息。由于老王事先主动像甲发送过数据,老王WAN的NAT记录了老王->甲的port为7777,所以老王能收到甲的数据包。这时候就能够P2P联系了。当然,如果其中一方ip或者port改变了,需要重新走一遍打洞的(1)~(4)流程。

以上即UDP打洞/NAT穿透的流程。上面文字内容较多,排版可能有点乱。如果有疑惑或者能指出我文章错误的,欢迎共同交流进步。

UDP通讯,外网向内网发消息,内网无法收到 [问题点数:20分,结帖人pylmcy150]

udp外网无法返回数据到内网 [问题点数:40分,结帖人qianshangding]

请教UDP 打洞是个什么过程,有成功过的请进。 [问题点数:100分,结帖人myth_2002]

求助技术贴:对称型NAT 怎么穿透

udp外网无法返回数据到内网 [问题点数:40分,结帖人qianshangding]

NAT的四种类型

对称NAT穿透的一种新方法

nat 类型及打洞原理

Linux NAT 类型详解

UDP通信在NAT中session保持时间测试

NAT与NAPT德区别。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有