http://www.360doc.com/content/12/0428/17/6187784_207328686.shtml
内容概述:在p2p通信领域中,由NAT(Network Address Translation,网络地址转换)引起的问题已经众所周知了,它会导致在NAT内部的p2p客户端在无论以何种有效的公网ip都无法访问的问题。虽 然目前已经发展出多种穿越NAT的技术,但相关的技术文档却很少,用来证明这些技术的稳定性和优点的实际数据更少。本文的目的在于描述和分析在实际中运用 得最广泛、最可靠同时也是最简单的一种NAT穿越技术,该技术通常被称为“打洞”技术。目前,“打洞”技术已经在UDP通信领域中得到了广泛的理解和应 用,在此,也将讨论如何利用它实现可靠的p2p的TCP流通信。在收集了大量的“打洞”技术可以穿越的NAT设备和网络的数据以后,我们发现82%的已测 NAT设备支持UDP形式的“打洞”穿越,64%的已测NAT设备支持TCP流形式的“打洞”穿越。由于重量级p2p应用程序(如,VOIP、BT、在线 游戏等)的用户需求量持续上升,并且该事实也已经引起了NAT设备生产厂商的广泛关注,因此,我们认为未来会有越来越多的NAT设备提供对“打洞”穿越技 术的支持。
1、介绍
用户量高速增长以及大量安全问题的巨大压力迫使Internet技术不断向前发展,但是这些新兴的技术很大程度地增加了应用程序开发的成本和复杂 性。Internet最初的地址体系是每个节点有一个唯一不变的全局地址,可以通过该地址直接与任何其它的节点进行通信,而现如今,该地址体系已经被新的 实际上广泛使用的地址体系所替换,新的地址体系是由全局地址域和通过NAT接入全局地址域的大量私有地址域组成。在新的地址体系中(如图1所示),只有在 “main”全局地址域中的节点可以在网络中很容易地与任何其它的拥有全局地址的节点通信,因为该节点拥有全局的、唯一的、可路由的地址。在私有网络中的 节点可以与在同一个私有网络中的其它节点进行通信,并且在通常情况下可以向全局地址中的某个“著名”的节点发起TCP连接或发送UDP数据包。NAT设备 在此扮演的角色就是为从内网向公网发起的连接的节点分配临时的转发session,将来自内网的数据包的地址和端口转换为公网的地址和端口,将来自公网的 数据包的地址和端口转换为内网的端口和地址,同时NAT将屏蔽所有未经授权的来自公网的数据包。
4 关于TCP打洞技术建立穿越NAT设备的p2p的TCP连接只比UDP复杂一点点,TCP协议的“打洞”从协议层来看是与UDP的“打洞”过程非常相似 的。尽管如此,基于TCP协议的打洞至今为止还没有被很好的理解,这也造成了对其提供支持的NAT设备不是很多。在NAT设备支持的前提下,基于TCP的 “打洞”技术实际上与基于UDP的“打洞”技术一样快捷、可靠。实际上,只要NAT设备支持的话,基于TCP的p2p技术的健壮性将比基于UDP的技术的 更强一些,因为TCP协议的状态机给出了一种标准的方法来精确的获取某个TCP session的生命期,而UDP协议则无法做到这一点。
4.1 套接字和TCP端口的重用实现基于TCP协议的p2p“打洞”过程中,最主要的问题不是来自于TCP协议,而是来自于来自于应用程序的API接口。这是由 于标准的伯克利(Berkeley)套接字的API是围绕着构建客户端/服务器程序而设计的,API允许TCP流套接字通过调用connect()函数来 建立向外的连接,或者通过listen()和accept函数接受来自外部的连接,但是,API不提供类似UDP那样的,同一个端口既可以向外连接,又能 够接受来自外部的连接。而且更糟的是,TCP的套接字通常仅允许建立1对1的响应,即应用程序在将一个套接字绑定到本地的一个端口以后,任何试图将第二个 套接字绑定到该端口的操作都会失败。为了让TCP“打洞”能够顺利工作,我们需要使用一个本地的TCP端口来监听来自外部的TCP连接,同时建立多个向外 的TCP连接。幸运的是,所有的主流操作系统都能够支持特殊的TCP套接字参数,通常叫做“SO_REUSEADDR”,该参数允许应用程序将多个套接字 绑定到本地的一个endpoint(只要所有要绑定的套接字都设置了SO_REUSEADDR参数即可)。BSD系统引入了SO_REUSEPORT参 数,该参数用于区分端口重用还是地址重用,在这样的系统里面,上述所有的参数必须都设置才行。
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发送给B。3、客户端A和B使用连接S的端口异步地发起向对方的公网、内网 endpoint的TCP连接,同时监听各自的本地TCP端口是否有外部的连接联入。4、A和B开始等待向外的连接是否成功,检查是否有新连接联入。如果 向外的连接由于某种网络错误而失败,如:“连接被重置”或者“节点无法访问”,客户端只需要延迟一小段时间(例如延迟一秒钟),然后重新发起连接即可,延 迟的时间和重复连接的次数可以由应用程序编写者来确定。5、TCP连接建立起来以后,客户端之间应该开始鉴权操作,确保目前联入的连接就是所希望的连接。 如果鉴权失败,客户端将关闭连接,并且继续等待新的连接联入。客户端通常采用“先入为主”的策略,只接受第一个通过鉴权操作的客户端,然后将进入p2p通 信过程不再继续等待是否有新的连接联入。
与UDP 不同的是,使用UDP协议的每个客户端只需要一个套接字即可完成与服务器S通信,并同时与多个p2p客户端通信的任务,而TCP客户端必须处理多个套接字 绑定到同一个本地TCP端口的问题,如图7所示。现在来看更加实际的一种情景,A与B分别位于不同的NAT设备后面,如图5所示,并且假定图中的端口号是 TCP协议的端口号,而不是UDP的端口号。图中向外的连接代表A和B向对方的内网endpoint发起的连接,这些连接或许会失败或者无法连接到对方。 如同使用UDP协议进行“打洞”操作遇到的问题一样,TCP的“打洞”操作也会遇到内网的IP与“伪”公网IP重复造成连接失败或者错误连接之类的问题。 客户端向彼此公网endpoint发起连接的操作,会使得各自的NAT设备打开新的“洞”允许A与B的TCP数据通过。如果NAT设备支持TCP“打洞” 操作的话,一个在客户端之间的基于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“打洞”的时候都发生了什么呢?假定A首先向B发出SYN包,该包发往B的公网 endpoint,并且被B的NAT设备丢弃,但是B发往A的公网endpoint的SYN包则通过A的NAT到达了A,然后,会发生以下的两种结果中的 一种,具体是哪一种取决于操作系统对TCP协议的实现:(1)A的TCP实现会发现收到的SYN包就是其发起连接并希望联入的B的SYN包,通俗一点来说 就是“说曹操,曹操到”的意思,本来A要去找B,结果B自己找上门来了。A的TCP协议栈因此会把B做为A向B发起连接connect的一部分,并认为连 接已经成功。程序A调用的异步connect()函数将成功返回,A的listen()等待从外部联入的函数将没有任何反映。此时,B联入A的操作在A程 序的内部被理解为A联入B连接成功,并且A开始使用这个连接与B开始p2p通信。由于收到的SYN包中不包含A需要的ACK数据,因此,A的TCP将用 SYN-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实现没有像(1)中所 讲的那么“智能”,它没有发现现在联入的B就是自己希望联入的。就好比在机场接人,明明遇到了自己想要接的人却不认识,误认为是其它的人,安排别人给接走 了,后来才知道是自己错过了机会,但是无论如何,人已经接到了任务已经完成了。然后,A通过常规的listen()函数和accept()函数得到与B的 连接,而由A发起的向B的公网endpoint的连接会以失败告终。尽管A向B的连接失败,A仍然得到了B发起的向A的连接,等效于A与B之间已经联通, 不管中间过程如何,A与B已经连接起来了,结果是A和B的基于TCP协议的p2p连接已经建立起来了。第一种结果适用于基于BSD的操作系统对于TCP的 实现,而第二种结果更加普遍一些,多数linux和windows系统都会按照第二种结果来处理。
[转]UDP/TCP穿越NAT的P2P通信方法研究(UDP/TCP打洞 Hole Punching)的更多相关文章
-
UDP穿越NAT原理(p2p)
转载自:http://blog.csdn.net/ldd909/article/details/5979967 论坛上经常有对P2P原理的讨论,但是讨论归讨论,很少有实质的东西产生(源代码).在这里我 ...
-
UDP方式实现广域网的P2P通信
最近在研究P2P通信,希望能够穿透路由器. 当前的做法只是使用TCP协议进行客户端与服务器端通信,使用UDP协议进行客户端之间的打洞操作,UDP的方式的源码在下方. 一直没有实现TCP的打洞,如果有实 ...
-
TCP实现P2P通信
Internet的迅速发展以及IPv4 地址数量的限制使得网络地址翻译(NAT,Network Address Trans2lation)设备得到广泛应用.NAT设备允许处于同一NAT后的多台主机共享 ...
-
P2P网络穿越 NAT穿越
http://blog.csdn.net/mazidao2008/article/details/4933730 ——————————————————————————————————————————— ...
-
P2P通信原理与实现(C++)
1.简介 当今互联网到处存在着一些中间件(MIddleBoxes),如NAT和防火墙,导致两个(不在同一内网)中的客户端无法直接通信.这些问题即便是到了IPV6时代也会存在,因为即使不需要NAT,但还 ...
-
p2p通信原理及实现(转)
1.简介 当今互联网到处存在着一些中间件(MIddleBoxes),如NAT和防火墙,导致两个(不在同一内网)中的客户端无法直接通信.这些问题即便是到了IPV6时代也会存在,因为即使不需要NAT,但还 ...
-
p2p通信原理及实现
1.简介 当今互联网到处存在着一些中间件(MIddleBoxes),如NAT和防火墙,导致两个(不在同一内网)中的客户端无法直接通信.这些问题即便是到了IPV6时代也会存在,因为即使不需要NAT,但还 ...
-
关于通信的关键词UDP/(TCP/IP)/IPC/RPC/.NET Remoting/WebService/WCF/Http 系列
OSI七层和TCP/IP四层的关系 1.1 OSI引入了服务.接口.协议.分层的概念,TCP/IP借鉴了OSI的这些概念建立TCP/IP模型. 1.2 OSI先有模型,后有协议,先有标准,后进行实践: ...
-
TCP和UDP并实现socket的简单通信
http://www.cnblogs.com/IPrograming/archive/2012/10/15/CSharp_Socket_4.html http://www.cnblogs.com/do ...
随机推荐
-
Windows程序设计之Hello,Windows 98程序的声音调试记录
最近在Window程序设计第五版,刚看到第三章,第三章中有一个程序调用了一个多媒体对象库winmm.lib库,由于该库不再默认项目中,如果不手动添加,编译时会提示错误而无法运行,但是书上用的是Visu ...
-
kindeditor在JavaWeb中的应用
KindEditor 是一套开源的在线HTML编辑器,主要用于让用户在网站上获得所见即所得编辑效果,开发人员可以用 KindEditor 把传统的多行文本输入框textarea替换为可视化的富文本编辑 ...
-
MongoDB实战指南(七):MongoDB复制集之复制集工作机制
http://www.cnblogs.com/longshiyVip/p/5097336.html 概述了复制集,整体上对复制集有了个概念,但是复制集最重要的功能之——自动故障转移是怎么实现的呢?数据 ...
-
JSON 的小技巧
有的时候上游传过来的字段是string类型的,但是我们却想用变成数字来使用. 本来用一个json:",string" 就可以支持了,如果不知道golang的这些小技巧,就要大费周章 ...
-
Centos6.5系统关闭防火墙
关闭Centos6.5系统防火墙步骤: 1.命令:service iptables stop //停止正在运行的防火墙服务 2.命令:chkconfig iptables off //永久关闭防火墙 ...
-
EasyUI 中 Combobox里的onChange和onSelect事件的区别
EasyUI 中 Combobox 选项发生改变时会触发 onChange,onSelect,onClick 3 个事件. 最近要做一个级联的 Combo 菜单,类似于选择地址时让用户填写省,市,区的 ...
-
angular ViewChild ContentChild 系列的查询参数
官方说明 官方文档 在调用 NgAfterViewInit 回调函数之前就会设置这些视图查询. 元数据属性: selector - 用于查询的指令类型或名字. read - 从查询到的元素中读取另一个 ...
-
(网页)HTML小技巧的一些小技巧
转自CSDN: 1.怎样定义网页语言(字符集)? 在制作网页过程中,你首先要定义网页语言,以便访问者浏览器自动设置语言,而我们用所见即所得的HTML工具时,都没有注意到这个问题, ...
-
Docker 网络不通的解决方法
表现是: docker主机内部网络正常,与其它主机的连接失效,其它主机不能连接docker主机上映射的端口,docker内部也无法连接外部主机. 执行docker info,可以看到一些警告. 可在不 ...
-
(原+转)linux安装rtl 8812au驱动
转载请注明出处: http://www.cnblogs.com/darkknightzh/p/6806917.html 参考网址: http://www.linuxdiyf.com/viewartic ...