《2022年穿越NAT的pp通信方法分析研究》由会员分享,可在线阅读,更多相关《2022年穿越NAT的pp通信方法分析研究(17页珍藏版)》请在金锄头文库上搜索。
1、1 / 17 内容概述:在 p2p 通信领域中,由NAT(Network Address Translation,网络地址转换 引起的问题已经众所周知了, 它会导致在NAT 内部的 p2p 客户端在无论以何种有效的公网ip 都无法访问的问题。虽然目前已经发展出多种穿越 NAT 的技术 ,但相关的技术文档却很少,用来证明这些技术的稳定性和优点的实际数据更少。本文的目的在于描述和分析在实际中运用得最广泛、最可靠同时也是最简单的一种NAT 穿越技术,该技术通常被称为“ 打洞 ” 技术。目前, “ 打洞 ” 技术已经在UDP 通信领域中得到了广泛的理解和应用,在此,也将讨论如何利用它实现可靠的p2p
2、的 TCP 流通信。在收集了大量的“ 打洞 ” 技术可以穿越的 NAT 设备和网络的数据以后,我们发现82% 的已测 NAT 设备支持UDP 形式的 “ 打洞 ” 穿越, 64% 的已测 NAT 设备支持TCP 流形式的 “ 打洞 ” 穿越。由于重量级p2p 应用程序 (如, VOIP 、 BT、在线游戏等 的用户需求量持续上升,并且该事实也已经引起了NAT 设备生产厂商的广泛关注,因此,我们认为未来会有越来越多的 NAT 设备提供对 “ 打洞 ” 穿越技术的支持。1、介绍用户量高速增长以及大量安全问题的巨大压力迫使Internet技术不断向前发展,但是这些新兴的技术很大程度地增加了应用程序开
3、发的成本和复杂性。Internet最初的地址体系是每个节点有一个唯一不变的全局地址,可以通过该地址直接与任何其它的节点进行通信,而现如今,该地址体系已经被新的实际上广泛使用的地址体系所替换,新的地址体系是由全局地址域和通过NAT 接入全局地址域的大量私有地址域组成。在新的地址体系中 如图 1 所示),只有在“main” 全局地址域中的节点可以在网络中很容易地与任何其它的拥有全局地址的节点通信,因为该节点拥有全局的、唯一的、可路由的地址。在私有网络中的节点可以与在同一个私有网络中的其它节点进行通信,并且在通常情况下可以向全局地址中的某个 “ 著名 ”的节点发起TCP 连接或发送UDP 数据包。
4、NAT 设备在此扮演的角色就是为从内网向公网发起的连接的节点分配临时的转发session ,将来自内网的数据包的地址和端口转换为公网的地址和端口,将来自公网的数据包的地址和端口转换为内网的端口和地址,同时NAT 将屏蔽所有未经授权的来自公网的数据包。精选学习资料 - - - - - - - - - 名师归纳总结 - - - - - - -第 1 页,共 17 页2 / 17 新的 Internet地址体系非常适合于“ 客户端 / 服务器 ” 这样的通信模式,一个典型的C/S 通信模式是:客户端在内网 私有地址域),服务器在公网 全局地址域),通过NAT 将内网和公网连接起来。这种地址体系使得在
5、不同内网 中最基本的要求。很显然,我们需要一种方法即使在NAT 设备存在的前提下,仍然能够无障碍地实现p2p 通信。在不同内网的两个节点之间建立p2p 连接的最有效的方法就是“ 打洞 ” 。该技术在基于UDP 的应用程序中得到了广泛的应用,同样的,该技术也可以用于基于TCP 的应用程序。有趣的是,与“ 打洞 ” 字面上的意思刚好相反,该技术不会影响到内网的安全。事实上,“ 打洞 ” 技术使得 p2p 软件的绝大部分功能都在 NAT 设备默认的安全策略的控制之下,这些都由NAT 设备建立的session来管理。本文阐述了适用于UDP 和 TCP 的“ 打洞 ” 技术,并详细描述了重要“ 打洞 ”
6、 过程中,应用程序和NAT设备之间的行为。不幸的是,由于NAT 设备的响应和行为不是标准的,所以没有任何技术可以穿越现有的所有 NAT 设备。本文提供了一些在现有NAT 设备上进行 “ 打洞 ” 的实验结果。我们收集的数据来自于互联网精选学习资料 - - - - - - - - - 名师归纳总结 - - - - - - -第 2 页,共 17 页3 / 17 上使用了“ NAT Check”工具并在大量不同生产厂商的NAT 设备上进行 “ 打洞 ” 实验的用户。由于数据是来自于一个叫做 “self - selecting” 的用户社区,或许不会完全代表在Internet上真正部署和使用的 NA
7、T 设备,但是结果无论如何还是很令人兴奋的。在做基本的 “ 打洞 ” 操作评估的时候,我们应该指出在现有的NAT 设备 “ 打洞 ” 的复杂度上,不同的复杂度会有不同的结果。但目前我们把讨论的重点集中于开发最简单的,可以应用于任何网络拓扑结构的、稳定的、有正确NAT 响应的 NAT 设备上的 “ 打洞 ” 技术。我们有意避免使用一些“ 聪明的小把戏 ” 通过欺骗某些 NAT 设备来达到短期内穿越较多的NAT 设备,但从长期来看会引起网络未知错误的技术。尽管引入IPv6 会极大地增加互联网的地址空间,从而减少对于NAT 设备的需求量,但短期内 IPv6确实增加了对 NAT 设备的需求量,因为NA
8、T 设备本身提供了一种方便的方法进行IPv4 与IPv6 地址域转换。另外私有网络上建立匿名和加密访问节点也有利于组织机构的安全性以及不受外界干扰,这些都意味着 NAT 还将存在相当长的一段时间。同样,防火墙技术也不会由于有了足够的ip 地址而消失,IPv6 的防火墙仍然会默认丢掉所有未经授权的数据包,仍然可以让在IPv6 环境下工作的应用程序“ 打洞 ” 。本文接下来的部分按照如下的方式组织:第二章介绍基本的NAT 穿越概念和术语;第三章介绍UDP “ 打洞 ” 过程;第四章介绍TCP“ 打洞 ” 过程;第五章介绍支持“ 打洞 ” 的 NAT 设备必须具有那些特性;第六章介绍我们在目前流行的
9、NAT 设备上的“ 打洞 ” 实验结果;第七章讨论相关的网络问题;第八章全文总结以及结束语。2、基本概念本节介绍了本文使用到的基本的NAT 术语,着重描述了适用于UDP 和 TCP 两种协议的通用的 NAT 穿越技术。2.1 、NAT 术语本文绝大部分术语和分类来自于RFC 2663定义,另外一些来自于较新的RFC 3489中的定义。理解 session是很重要的。一个TCP 或 UDP 的 session endpoint是由一个IP 地址,端口号组成,精选学习资料 - - - - - - - - - 名师归纳总结 - - - - - - -第 3 页,共 17 页4 / 17 每个 ses
10、sion是由两个session endpoint构成。从内网节点的角度来看,一个session由 4 部分组成分别为:本地IP ,本地端口,远端IP,远端端口。session的方向通常代表了数据包的初始流动的方向;对于TCP 来说就是SYN 包的流向,对于UDP 来说就是第一个用户数据包的流向。NAT 有很多种,但最普遍的一种类型叫做“ 传统 ” NAT ,或者 “ 向外 ” NAT 。他们在内网和公网之间提供了一个 “ 不对称 ” 桥的映射。 “ 向外 ”NAT在默认情况下只允许向外的session穿越 NAT :从外向内的的数据包都会被丢弃掉,除非NAT 设备事先已经定义了这些从外向内的数
11、据包是已存在的内网session的一部分。“ 外向 ” NAT 会造成 p2p 协议的混乱,因为当p2p 的双方决定向在不同NAT 后面的对方开始通信的时候,无论哪一方试图初始化一个session ,另一方的NAT 都会拒绝这个请求。NAT 穿越的核心思想就是让p2p 的双方的NAT 看上去都是 “ 向外 ” 的 NAT 。“ 向外 ” NAT 有两种类型:1 )“ 基础 ” NAT ,该 NAT 只转换 IP 地址,不转换端口号。 NAPT 转换整个 session endpoints。由于 NAPT 允许内网的多个节点通过共享的方式使用同一个的公共的 IP 地址,因此,支持NAPT 的 N
12、AT 设备才会越来越多。尽管本文通篇讨论的内容都是基于支持 NAPT 的NAT 设备的,但这些规律和技术同样适用于“ 基础 ” NAT 。2.2 转发方式最可靠但同时也是效率最低的p2p 穿越 NAT 进行通信的方法是采用类似C/S 方式的转发。假定两个节点A 和 B 每个节点都有向外的TCP 或 UDP 连接,联入公共的已知服务器S,S 的公网 IP地址是 18.181.0.31,端口号是1234如图 2 所示) ,每个客户端位于不同的私有内网中,并且它们的NAT 设备妨碍了客户端之间直接的p2p 连接。做为对直连方案的替代方案,两个客户端可以利用公共的服务器S 进行消息的转发。例如,A 为
13、了将消息送给B,A 只需将消息发给S,然后由S 转发给 B,这一过程将使用A 与B 事先与 S 建立好的连接。精选学习资料 - - - - - - - - - 名师归纳总结 - - - - - - -第 4 页,共 17 页5 / 17 转发方式通常只能在双方客户端都连接到服务器的时候有效。这种方式的缺点在于,它假定服务器的处理能力和网络带宽以及通信延迟都是理想的情况下,不会受到客户端个数的影响。但是,由于没有其它的方法能够像转发方式那样,可以穿越现存的所有NAT 设备,因此在构建高可靠性的 p2p 系统的时候,通过服务器转发的方式依旧是一个非常有用的保证系统可靠性的方法。TURN 协议定义了
14、如何实现安全的转发方式。2.3 反向连接方式一些 p2p 的应用程序采用了直接但是有所限制的技术来实现NAT 穿越,该技术叫做“ 反向连接 ” ,这是用于当两个节点联入服务器S 的时候,只有一个一个节点在NAT 设备的后面 如图 3 所示)。如果A 希望建立与B 的连接,那么A 可以直接联入B,因为 B 是在公网中存在的,没有经过NAT 转换,而且 A 的 NAT 设备也允许A 直接由内网发起向外网的连接。如果B 希望建立与A 的连接,很不幸,A 的 NAT 设备会阻止该操作,此时,B 可以借助于转发服务器S,向 A 发送 “ 反向连接 ” 请求,由 A“ 主动 ” 连接 B,从而达到A与 B
15、 的 p2p 通信的目的。精选学习资料 - - - - - - - - - 名师归纳总结 - - - - - - -第 5 页,共 17 页6 / 17 尽管该技术的局限性非常明显,但是使用已知的服务器做为中介辅助p2p 客户端双方进行p2p 连接的思想已经成为了更加通用的“ 打洞 ” 技术的基本思想。3 UDP 打洞方式即使两个 p2p 客户端都位于NAT 设备后面, UDP 打洞方式也能够通过已知的服务器实现p2p 客户端直连。该技术在RFC 3027的第 5.1 节中曾有所提及,在网络上可以找到对其较模糊的描述,在最近的 IP 协议实验中得到应用,在多种在线游戏协议中得到了应用。3.1
16、集中服务器打洞技术假定客户端A 和 B 可以与公网内的已知的集中服务器建立UDP 连接 可以互发UDP 数据包)。当一个客户端在S 上登陆的时候,服务器记录下该客户端的两个endpoints 1 )A 最初不知道如何向B 发起连接,于是A 向服务器S 发送消息,请求S 帮助建立与B 的 UDP 连接。2 )S 将含有 B 的公网和内网的endpoint发给 A,同时, S 将含有 A 的公网和内网的endpoint的用于请求连接的消息也发给B。一旦这些消息顺利到达,A 与 B 就都知道了对方的公网和内网的endpoint。3 )当 A 收到由 S 发来的包含B 的公网和内网endpoint的消
17、息, A 开始向这些B 的endpoint发送 UDP 数据包,并且 A 会自动锁定第一个给出响应的B 的 endpoint。同理,当B 收到由 S 发来的 A 的公网和内网endpoint 以后,也会开始向A 的公网和内网的endpoint发送 UDP 数据包,并且自动锁定第一个得到 A 的回应的endpoint。由于 A 与 B 的互相向对方发送UDP 数据包的操作是异步的,所以A 和 B 发送数据包的时间先后并没有严格的时序要求。下面我们就来看一下这三个角色之间是如何进行UDP “ 打洞 ” 的。在这里我们分为三种具体情景来讨论:第一种也是最 “ 简单 ” 的一种情景,两个客户端都位于同
18、一个NAT 设备后面,位于同一个内网中;第二种也是最普遍的一种情景,两个客户端分别位于不同的NAT 设备后面,分属不同的内网;第三种是客户端位于两层NAT 设备之后,通常最上层的NAT 是由 ISP 网络提供商,第二层的 NAT 是家用的 NAT 路由器之类的设备。通常情况下由应用程序自身确定的网络物理层连接方式是很困难的,有时甚至是不可能的,即使是上述的若干种情景下可以穿越NAT ,也只是代表在一定时期内有效,而不是永久有效的。诸如STUN 之类的网络协议或许可以提供必要的NAT 信息,但在遇到多层NAT 设备的时候,通常这些信息也不是完全完整和有效的。精选学习资料 - - - - - -
19、- - - 名师归纳总结 - - - - - - -第 7 页,共 17 页8 / 17 尽管如此,只要NAT 设备的响应是“ 合理 ” 的,在通常情况下“ 打洞 ” 技术还是能够在应用程序对网络状况一无所知的前提下自动适用于多数场合。“合理 ” 的 NAT 响应将在第五章中详细讨论)3.3 p2p客户端位于同一个NAT 设备后面首先假设两个客户端位于同一个NAT 设备后面,并且位于相同的内网 假设 A 想通过服务器S 做为介绍人,发起对B 的连接。 A 向 S 发出消息请求与B 进行连接。 S 将 B 的公网 endpoint 即公网 ip 和 port )以及内网endpoint即内网 i
20、p 和 port )发给 A,同时把A 的公网、内网的endpoints发给 B。由 A 和 B 发往对方公网endpoint的 UDP 数据包能否被对方收到,这取决于当前的NAT 是否支持 “ 发夹 ” 转换 本地 IP:10.0.0.1,本地端口 :4321,公网 IP:155.99.25.11,公网端口: 62000 客户端 B- 本地 IP:10.1.1.3,本地端口 :4321,公网 IP:138.76.29.7,公网端口: 31000 ( 图 5 在 A 向服务器S 发送的登陆消息体中,会包含A 的内网 endpoint信息,即10.0.0.1:4321;服务器 S 会记录下A 的
21、内网 endpoint,同时会把自己观察到的A 的公网 endpoint记录下来,即 155.99.25.11:62000。同理,服务器S 会记录下B 的内网 endpoint,10.1.1.3:4321和由 S 观察到的B 的公网 endpoint,138.76.29.7:31000。无论 A 与 B 二者任何一方向S 发送p2p 连接请求,服务器都会将其记录下来的上述的公网、内网endpoint发送给 A、B。精选学习资料 - - - - - - - - - 名师归纳总结 - - - - - - -第 9 页,共 17 页10 / 17 由于 A、B 分属不同的内网,它们彼此的内网endp
22、oint无法在公网中路由,所以发往各自内网 endpoint的 UDP 数据包会发送到错误的主机或者根本不存在的主机。因此应用程序对于收到的消息必须经过授权和过滤,只有通过授权的的消息才能是从对方的endpoint 发出来的,例如,可以在消息中加入对方的程序名称、加密算法,或者至少是一个双方都从服务器S 上的预先得到的随机数字。现在假定A 的第一个消息将发往B 的公网 endpoint,如图 5 所示。该消息途经A 的NAT 设备,并在该设备上生成了一个“ 向外 ” 的 session 。新的 session源 endpoint是10.0.0.1:4321 该 endpoint和 A 与服务器
23、 S 的建立连接的时候NAT 生成的源endpoint一样,但它的目的endpoint不同。如果A 的 NAT 设备给出的响应是“ 友好 ” 的,那么 A 的 NAT 设备将保留A 的内网 endpoint,并且所有来自A 的源 endpoint10.0.0.1:4321)的数据包都沿用A 与 S 事先建立起来的session ,公网 endpoint均为 155.99.25.11:62000)。A 向 B 的公网 endpoint发送消息的过程就是“ 打洞 ” 的过程,从A 的内网的角度来看应为从10.0.0.1:4321)发往 138.76.29.7:31000),从 A 的在其 NAT
24、设备上建立的session 来看,是从 155.99.25.11:62000)发到 138.76.29.7: 31000 )。如果 A 发给 B 的公网 endpoint的消息包在B 向 A 发送消息包之前到达B 的 NAT 设备,B 的 NAT 会认为 A 发过来的消息是未经授权的公网消息,会丢弃掉该数据包。B 发往 A 的消息包根上述的过程一样,会在B 的 NAT 上建立一个 10.1.1.3:4321 ,155.99.25.11:62000)的 session提供的工业级的NAT 设备, NAT C 提供将多个下属的用户NAT 或用户节点映射到有限的几个公网IP 的服务, NAT A 和
25、 NAT B做为NAT C 的内网节点将把用户的家庭网络或内部网络接入NAT C的内网,然后用户的内部网络就可以经由 NAT C 访问公网了。从这种拓扑结构上来看,只有服务器S 与 NAT C 是真正拥有公网可路由IP地址的设备,而 NAT A和 NAT B 所使用的 “ 公网 ”IP地址,实际上是由ISP 服务提供商设定的相对于 NAT C 而言)内网地址 本位的后续部分我把这个由ISP 提供的内网地址相对于NAT A和 NAT B 称之为“ 伪” 公网地址),同理隶属于NAT A 与 NAT B 的客户端,相对与NAT A , NAT B 而言,它们处于NAT A ,NAT B的内网,以此
26、类推,客户端可以放到到多层NAT 设备后面。客户端A 和客户端 B 发起对服务器S 的连接的时候,就会依次在NAT A 和 NAT B上建立向外的session ,而NAT A 、NAT B 要联入公网的时候,会在NAT C上再建立向外的session 。 图 6 )现在假定客户端A 和 B 希望通过UDP “ 打洞 ” 完成两个客户端的p2p 直连。最优化的路由策略是客户端 A 向客户端B 的“ 伪公网 ”IP上发送数据包,即ISP 服务提供商指定的内网IP ,NAT B 的“ 伪” 公网 endpoint,10.0.1.2:55000。由于从服务器S 的角度只能观察到真正的公网地址,也就是
27、 NAT A ,NAT B在 NAT C建立的 session的真正的公网地址精选学习资料 - - - - - - - - - 名师归纳总结 - - - - - - -第 11 页,共 17 页12 / 17 155.99.25.11:62000以及155.99.25.11:62005,所以非常不幸,客户端A 与客户端B 是无法通过服务器S 知道这些“ 伪” 公网的地址的。而且即使客户端A 和 B 通过某种手段可以得到NAT A 和 NAT B的“ 伪” 公网地址,我们仍然不建议采用上述的“ 最优化 ” 的打洞方式,这是因为这些地址是由ISP 服务提供商提供的或许会存在与客户端本身所在的内网地
28、址重复的可能性。 例如: NAT A的内网的 IP 地址域恰好与NAT A 在 NAT C的“ 伪 ” 公网 IP 地址域重复,这样就会导致打洞数据包无法发出的问题)因此客户端别无选择,只能使用由公网服务器S 观察到的 A,B 的公网 endpoint进行 “ 打洞”操作,用于 “ 打洞 ” 的数据包将由NAT C 进行转发,这里NAT C是否支持 “ 发夹 ” 转换或 “ 环路”转换非常重要,否则数据包将无法由NAT C 转发给 NAT A 和 NAT B ,进而无法到达客户端 A 和 B。当客户端A 向客户端B 的公网 endpoint155.99.25.11:62005)发送 UDP 数
29、据包的时候, NAT A 首先把数据包的源endpoint由 A 的内网 endpoint10.0.0.1:4321)转换为 “ 伪” 公网endpoint 套接字的API 是围绕着构建客户端/服务器程序而设计的, API 允许 TCP 流套接字通过调用connect(函数来建立向外的连接,或者通过 listen(和accept函数接受来自外部的连接,但是,API 不提供类似UDP 那样的,同一个端口既可以向外连接,又能够接受来自外部的连接。而且更糟的是,TCP 的套接字通常仅允许建立1 对 1 的响应,即应用程序在将一个套接字绑定到本地的一个端口以后,任何试图将第二个套接字绑定到该端口的操作
30、都会失败。为了让 TCP “打洞 ” 能够顺利工作,我们需要使用一个本地的TCP 端口来监听来自外部的TCP 连接,同时建立多个向外的TCP 连接。幸运的是,所有的主流操作系统都能够支持特殊的TCP 套接字参数,通常叫做 “SO_REUSEADDR”,该参数允许应用程序将多个套接字绑定到本地的一个endpoint只要所有要绑定的套接字都设置了SO_REUSEADDR参数即可)。BSD 系统引入了SO_REUSEPORT参数 ,该参数用于区分精选学习资料 - - - - - - - - - 名师归纳总结 - - - - - - -第 13 页,共 17 页14 / 17 端口重用还是地址重用,在
31、这样的系统里面,上述所有的参数必须都设置才行。4.2 打开 p2p 的 TCP 流假定客户端A 希望建立与B 的 TCP 连接。我们像通常一样假定A 和 B 已经与公网上的已知服务器S 建立了 TCP 连接。服务器记录下来每个联入的客户端的公网和内网的endpoints,如同为UDP 服务的时候一样。从协议层来看,TCP “打洞 ” 与 UDP “ 打洞 ” 是几乎完全相同的过程。1、客户端A 使用其与服务器S 的连接向服务器发送请求,要求服务器S 协助其连接客户端 B。2、S 将 B 的公网和内网的TCP endpoint返回给 A,同时, S 将 A 的公网和内网的endpoint发送给
32、B。3、客户端A 和 B 使用连接 S 的端口异步地发起向对方的公网、内网endpoint的 TCP 连接,同时监听各自的本地TCP 端口是否有外部的连接联入。4、A 和 B 开始等待向外的连接是否成功,检查是否有新连接联入。如果向外的连接由于某种网络错误而失败,如:“ 连接被重置 ” 或者 “ 节点无法访问 ” ,客户端只需要延迟一小段时间 例如延迟一秒钟),然后重新发起连接即可,延迟的时间和重复连接的次数可以由应用程序编写者来确定。5、TCP 连接建立起来以后,客户端之间应该开始鉴权操作,确保目前联入的连接就是所希望的连接。如果鉴权失败,客户端将关闭连接,并且继续等待新的连接联入。客户端通
33、常采用“ 先入为主 ” 的策略,只接受第一个通过鉴权操作的客户端,然后将进入p2p 通信过程不再继续等待是否有新的连接联入。精选学习资料 - - - - - - - - - 名师归纳总结 - - - - - - -第 14 页,共 17 页15 / 17 图 7 )与 UDP 不同的是,使用UDP 协议的每个客户端只需要一个套接字即可完成与服务器S 通信,并同时与多个p2p 客户端通信的任务,而TCP 客户端必须处理多个套接字绑定到同一个本地TCP 端口的问题,如图7 所示。现在来看更加实际的一种情景,A 与 B 分别位于不同的NAT 设备后面,如图5 所示,并且假定图中的端口号是TCP 协议
34、的端口号,而不是UDP 的端口号。图中向外的连接代表A 和 B 向对方的内网endpoint发起的连接,这些连接或许会失败或者无法连接到对方。如同使用UDP 协议进行“ 打洞 ”操作遇到的问题一样,TCP 的“ 打洞 ” 操作也会遇到内网的IP 与“ 伪” 公网 IP 重复造成连接失败或者错误连接之类的问题。客户端向彼此公网endpoint发起连接的操作,会使得各自的NAT 设备打开新的“ 洞 ” 允许A 与 B 的精选学习资料 - - - - - - - - - 名师归纳总结 - - - - - - -第 15 页,共 17 页16 / 17 TCP 数据通过。如果NAT 设备支持TCP“
35、打洞 ” 操作的话,一个在客户端之间的基于TCP协议的流通道就会自动建立起来。如果A 向 B 发送的第一个SYN 包发到了B 的 NAT 设备,而B在此前没有向A 发送 SYN 包, B 的 NAT 设备会丢弃这个包,这会引起A 的“ 连接失败 ” 或“ 无法连接 ” 问题。而此时,由于 A 已经向 B 发送过 SYN 包, B 发往 A 的 SYN 包将被看作是由A 发往 B 的包的回应的一部分,所以 B 发往 A 的 SYN 包会顺利地通过A 的 NAT 设备,到达A,从而建立起A 与 B 的p2p 连接。4.3 从应用程序的角度来看TCP“ 打洞 ”从应用程序的角度来看,在进行TCP “
36、打洞 ” 的时候都发生了什么呢?假定A 首先向 B 发出SYN 包,该包发往B 的公网 endpoint,并且被B 的 NAT 设备丢弃,但是B 发往 A 的公网endpoint的 SYN 包则通过 A 的 NAT 到达了 A,然后,会发生以下的两种结果中的一种,具体是哪一种取决于操作系统对 TCP 协议的实现: 函数将成功返回,A 的 listen(等待从外部联入的函数将没有任何反映。此时,B 联入 A的操作在 A 程序的内部被理解为A 联入 B 连接成功,并且A 开始使用这个连接与B 开始 p2p 通信。由于收到的SYN 包中不包含A 需要的 ACK 数据,因此,A 的 TCP 将用 SY
37、N-ACK包回应 B 的公网 endpoint,并且将使用先前A 发向 B 的 SYN 包一样的序列号。一旦B 的 TCP 收到由 A 发来的 SYN-ACK 包,则把自己的 ACK 包发给 A,然后两端建立起TCP 连接。简单的说,第一种,就是即使A 发往 B 的SYN 包被 B 的 NAT 丢弃了,但是由于B 发往 A 的包到达了A。结果是, A 认为自己连接成功了,B 也认为自己连接成功了,不管是谁成功了,总之连接是已经建立起来了。2 )另外一种结果是,A 的 TCP 实现没有像 函数和 accept(函数得到与B 的连接,而由A 发起的向B 的公网 endpoint的连接会以失败告终。尽管A 向 B 的连接失败,A 仍然得到了B 发起的向 A 的连接,等效于 A 与 B 之间已经联通,不管中间过程如何,A 与 B 已经连接起来了,结果是A 和B 的基于 TCP 协议的 p2p 连接已经建立起来了。第一种结果适用于基于BSD 的操作系统对于TCP 的实现,而第二种结果更加普遍一些,多数 linux和windows系统都会按照第二种结果来处理。精选学习资料 - - - - - - - - - 名师归纳总结 - - - - - - -第 17 页,共 17 页