`
wan_2004
  • 浏览: 140883 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

UDP 打洞技术

    博客分类:
  • C++
阅读更多

首先先介绍一些基本概念:
    NAT(Network Address Translators)
,网络地址转换:网络地址转换是在IP 地址日益缺乏的情况下产生的,它的主要目的就是为了能够地址重用。NAT 分为两大类,基本的NATNAPT(Network Address/Port Translator)
   
最开始NAT 是运行在路由器上的一个功能模块。
   
最先提出的是基本的NAT ,它的产生基于如下事实:一个私有网络(域)中的节点中只有很少的节点需要与外网连接(呵呵,这是在上世纪90 年代中期提出的)。那么这个子网中其实只有少数的节点需要全球唯一的IP 地址,其他的节点的IP 地址应该是可以重用的。
   
因此,基本的NAT 实现的功能很简单,在子网内使用一个保留的IP 子网段,这些IP 对外是不可见的。子网内只有少数一些IP 地址可以对应到真正全球唯一的IP 地址。如果这些节点需要访问外部网络,那么基本NAT 就负责将这个节点的子网内IP 转化为一个全球唯一的IP 然后发送出去。( 基本的NAT 会改变IP 包中的原IP 地址,但是不会改变IP 包中的端口 )
   
关于基本的NAT 可以参看
RFC 1631
   
另外一种NAT 叫做NAPT ,从名称上我们也可以看得出,NAPT 不但会改变经过这个NAT 设备的IP 数据报的IP 地址,还会改变IP 数据报的TCP/UDP 端口。基本NAT 的设备可能我们见的不多(呵呵,我没有见到过),NAPT 才是我们真正讨论的主角。看下图:

                                Server S1                        
                         18.181.0.31:1235                         
                                      |
          ^  Session 1 (A-S1)  ^      | 
          |  18.181.0.31:1235  |      |  
          v 155.99.25.11:62000 v      |   
                                      |
                                     NAT
                                 155.99.25.11
                                      |
          ^  Session 1 (A-S1)  ^      | 
          |  18.181.0.31:1235  |      | 
          v   10.0.0.1:1234    v      | 
                                      |
                                   Client A
                                10.0.0.1:1234
   
有一个私有网络10.*.*.*Client A 是其中的一台计算机,这个网络的网关(一个NAT 设备)的外网IP155.99.25.11( 应该还有一个内网的IP 地址,比如10.0.0.10) 。如果Client A 中的某个进程(这个进程创建了一个UDP Socket, 这个Socket 绑定1234 端口)想访问外网主机18.181.0.311235 端口,那么当数据包通过NAT 时会发生什么事情呢?
   
首先NAT 会改变这个数据包的原IP 地址,改为155.99.25.11 。接着NAT 会为这个传输创建一个SessionSession 是一个抽象的概念,如果是TCP ,也许Session 是由一个SYN 包开始,以一个FIN 包结束。而UDP 呢,以这个IP 的这个端口的第一个UDP 开始,结束呢,呵呵,也许是几分钟,也许是几小时,这要看具体的实现了)并且给这个Session 分配一个端口,比如62000 ,然后改变这个数据包的源端口为62000 。所以本来是(10.0.0.1:1234->18.181.0.31:1235 )的数据包到了互联网上变为了(155.99.25.11:62000->18.181.0.31:1235 )。
   
一旦NAT 创建了一个Session 后,NAT 会记住62000 端口对应的是10.0.0.11234 端口,以后从18.181.0.31 发送到62000 端口的数据会被NAT 自动的转发到10.0.0.1 上。(注意:这里是说18.181.0.31 发送到62000 端口的数据会被转发,其他的IP 发送到这个端口的数据将被NAT 抛弃)这样Client A 就与Server S1 建立以了一个连接。

    呵呵,上面的基础知识可能很多人都知道了,那么下面是关键的部分了。
   
看看下面的情况:
    Server S1                                     Server S2
 18.181.0.31:1235                              138.76.29.7:1235
        |                                             |
        |                                             |
        +----------------------+----------------------+
                               |
   ^  Session 1 (A-S1)  ^      |      ^  Session 2 (A-S2)  ^
   |  18.181.0.31:1235  |      |      |  138.76.29.7:1235  |
   v 155.99.25.11:62000 v      |      v 155.99.25.11:62000 v
                               |
                            Cone NAT
                          155.99.25.11
                               |
   ^  Session 1 (A-S1)  ^      |      ^  Session 2 (A-S2)  ^
   |  18.181.0.31:1235  |      |      |  138.76.29.7:1235  |
   v   10.0.0.1:1234    v      |      v   10.0.0.1:1234    v
                               |
                            Client A
                         10.0.0.1:1234
   
接上面的例子,如果Client A 的原来那个Socket( 绑定了1234 端口的那个UDP Socket) 又接着向另外一个Server S2 发送了一个UDP 包,那么这个UDP 包在通过NAT 时会怎么样呢?
   
这时可能会有两种情况发生,一种是NAT 再次创建一个Session ,并且再次为这个Session 分配一个端口号(比如:62001 )。另外一种是NAT 再次创建一个Session ,但是不会新分配一个端口号,而是用原来分配的端口号62000 。前一种NAT 叫做Symmetric NAT ,后一种叫做Cone NAT 。我们期望我们的NAT 是第二种,呵呵,如果你的NAT 刚好是第一种,那么很可能会有很多P2P 软件失灵。(可以庆幸的是,现在绝大多数的NAT 属于后者,即Cone NAT
  
   
好了,我们看到,通过NAT, 子网内的计算机向外连结是很容易的(NAT 相当于透明的,子网内的和外网的计算机不用知道NAT 的情况)。
   
但是如果外部的计算机想访问子网内的计算机就比较困难了(而这正是P2P 所需要的)。
   
那么我们如果想从外部发送一个数据报给内网的计算机有什么办法呢?首先,我们必须在内网的NAT 上打上一个 (也就是前面我们说的在NAT 上建立一个Session ),这个洞不能由外部来打,只能由内网内的主机来打。而且这个洞是有方向的,比如从内部某台主机(比如:192.168.0.10 )向外部的某个IP( 比如:219.237.60.1) 发送一个UDP 包,那么就在这个内网的NAT 设备上打了一个方向为219.237.60.1 ,(这就是称为UDP Hole Punching 的技术)以后219.237.60.1 就可以通过这个洞与内网的192.168.0.10 联系了。(但是其他的IP 不能利用这个洞)。

呵呵,现在该轮到我们的正题P2P 了。有了上面的理论,实现两个内网的主机通讯就差最后一步了:那就是鸡生蛋还是蛋生鸡的问题了,两边都无法主动发出连接请求,谁也不知道谁的公网地址,那我们如何来打这个洞呢?我们需要一个中间人来联系这两个内网主机。
   
现在我们来看看一个P2P 软件的流程,以下图为例:

                       Server S 219.237.60.1
                          |
                          |
   +----------------------+----------------------+
   |                                             |
 NAT A (
外网IP:202.187.45.3)                 NAT B ( 外网 IP:187.34.1.56)
   |   (
内网IP:192.168.0.1)                      | ( 内网
IP:192.168.0.1)
   |                                             |
Client A  (192.168.0.20:4000)             Client B (192.168.0.10:40000)

    首先, Client A 登录服务器, NAT A 为这次的 Session 分配了一个端口 60000 ,那么 Server S 收到的 Client A 的地址是 202.187.45.3:60000 ,这就是 Client A 的外网地址了。同样, Client B 登录 Server S NAT B 给此次 Session 分配的端口是 40000 ,那么 Server S 收到的 B 的地址是 187.34.1.56:40000
   
此时, Client A Client B 都可以与 Server S 通信了。如果 Client A 此时想直接发送信息给 Client B ,那么他可以从 Server S 那儿获得 B 的公网地址 187.34.1.56:40000 ,是不是 Client A 向这个地址发送信息 Client B 就能收到了呢?答案是不行,因为如果这样发送信息, NAT B 会将这个信息丢弃(因为这样的信息是不请自来的,为了安全,大多数 NAT 都会执行丢弃动作)。现在我们需要的是在 NAT B 上打一个方向为 202.187.45.3 (即 Client A 的外网地址)的洞,那么 Client A 发送到 187.34.1.56:40000 的信息 ,Client B 就能收到了。这个打洞命令由谁来发呢,呵呵,当然是 Server S
   
总结一下这个过程:如果 Client A 想向 Client B 发送信息,那么 Client A 发送命令给 Server S ,请求 Server S 命令 Client B Client A 方向打洞。呵呵,是不是很绕口,不过没关系,想一想就很清楚了,何况还有源代码呢(侯老师说过:在源代码面前没有秘密 8 )),然后 Client A 就可以通过 Client B 的外网地址与 Client B 通信了。
   
   
注意:以上过程只适合于 Cone NAT 的情况,如果是 Symmetric NAT ,那么当 Client B Client A 打洞的端口已经重新分配了, Client B 将无法知道这个端口(如果 Symmetric NAT 的端口是顺序分配的,那么我们或许可以猜测这个端口号,可是由于可能导致失败的因素太多,我们不推荐这种猜测端口的方法)。


看更多:http://www.cppblog.com/shootingstars/archive/2007/06/12/26140.html

分享到:
评论

相关推荐

    UDP打洞技术例程(C++)

    UDP打洞(P2P)C++实例,配有详细的注释,可以在此基础上继续进行二次开发。

    UDP打洞技术资料合集

    UDP打洞技术是一种在NAT(网络地址转换)环境下实现两个内部网络节点间直接通信的方法。在即时通讯领域,如P2P网络、在线游戏或VoIP应用中,UDP打洞技术尤其重要,因为它可以绕过NAT的限制,使得位于不同NAT后的设备...

    C#UDP打洞UDP打洞C#UDP打洞UDP打洞UDP打洞UDP打洞

    UDP打洞技术是一种在NAT(网络地址转换)环境下实现两个位于不同内网的设备间直接通信的方法。在互联网上,许多设备通过NAT连接,这使得它们不能直接与外部网络中的其他设备通信,因为它们都有相同的公共IP地址。UDP...

    VB版UDP打洞演示(转载)

    UDP打洞技术是一种在NAT(网络地址转换)环境下实现两个私有网络内主机之间直接通信的方法。在VB(Visual Basic)中实现UDP打洞,主要是通过编程来规避NAT的限制,使得两台位于不同NAT后的计算机可以相互通信,而...

    udp.zip_ICE NAT_UDP nat java_nat_udp打洞_最新防火墙

    就是非常有名的“UDP打洞技术”,UDP打洞技术依赖于由公共防火墙和cone NAT,允许适当的有计划的端对端应用程序通过NAT“打洞”,即使当双方的主机都处于NAT之后。这种技术在 RFC3027的5.1节[NAT PROT] 中进行了重点...

    udp打洞原理详解

    本文将详细介绍UDP打洞技术的基本原理及其应用场景,帮助读者理解如何实现在NAT环境下的点对点通信。 #### 一、UDP打洞技术背景 在最初的互联网设计中,每一个节点都被赋予了一个全球唯一的IP地址,这使得任何两个...

    UDP打洞的p2p聊天程序

    UDP打洞技术是一种在NAT(网络地址转换)环境下实现P2P(点对点)通信的方法,尤其在建立直接连接以提高传输效率和降低服务器压力方面显得尤为重要。在这个场景中,我们有一个由服务器和客户端组成的聊天程序,利用...

    UDP打洞软件

    UDP打洞技术是一种在内网环境下,通过利用UDP(User Datagram Protocol)协议,使得两个不在同一公网IP下的设备能够直接通信的技术。它主要用于解决NAT(Network Address Translation)环境下的点对点通信问题。NAT...

    UDP穿越NAT,UDP打洞

    ### UDP穿越NAT与UDP打洞技术解析及C#实现 #### 一、UDP穿越NAT与UDP打洞概述 在网络通信中,由于NAT(Network Address Translation)的存在,两个位于不同私有网络中的主机之间很难直接进行UDP通信。为了克服这一...

    java udp p2p nat 等打洞技术实现通信,已测试成功

    UDP打洞技术是一种在NAT(网络地址转换)环境下实现P2P(点对点)通信的方法,尤其在处理子网间通信时非常有用。在Java中,我们可以利用其强大的网络编程API来实现这一功能。以下是对这个技术的详细解释。 ### UDP...

    C语言实现UDP打洞代码

    UDP打洞技术是一种在NAT(网络地址转换)环境下实现两个私有IP地址之间直接通信的方法,常用于P2P(点对点)通信。在本文中,我们将深入探讨C语言实现UDP打洞的原理、步骤以及代码实现的关键点。 首先,理解UDP打洞...

    C#实现UDP打洞

    从给定的文件信息来看,本文旨在探讨如何利用C#编程语言实现UDP打洞技术,这一技术在网络编程领域尤其是P2P(Peer-to-Peer)网络中扮演着至关重要的角色。UDP打洞,又称NAT(Network Address Translation)穿越或NAT...

    udp打洞源码服务端和客户端C# 实现

    UDP打洞技术是一种在NAT(网络地址转换)环境下实现两个私有网络主机之间直接通信的方法,常用于P2P应用、多人在线游戏等场景。本文将深入探讨C#实现的UDP打洞服务端和客户端的关键知识点。 1. **UDP基础**: UDP...

    UDP打洞的实现代码

    UDP打洞技术是一种在P2P网络中实现端到端通信的方法,特别是在存在网络地址转换(NAT)的环境中。NAT使得私有网络内的设备无法直接与其他网络的设备通信,因为它们都共享一个公共IP地址。UDP打洞通过利用NAT的某些...

    UDP打洞源码及原理分析.zip

    UDP打洞技术是一种在NAT(网络地址转换)环境下实现两个位于不同内网的设备间直接通信的方法。在互联网上,许多用户设备由于IP地址稀缺,通常会通过NAT进行地址转换,这使得它们不能直接与其他内网设备通信。UDP打洞...

    P2P之UDP打洞穿透NAT的源代码

    UDP打洞技术是一种在NAT(网络地址转换)环境下实现P2P(点对点)通信的方法。在NAT环境中,内部网络的设备通常没有全局唯一的公网IP,而是通过一个公共IP来对外通信,这就导致了两个处于NAT后的设备无法直接通信。...

    TCP/UDP打洞

    ### TCP/UDP打洞技术详解 #### 一、引言 随着互联网的快速发展和技术进步,P2P(Peer-to-Peer)通信已成为一种常见的网络应用形式。然而,NAT(Network Address Translation,网络地址转换)的存在给P2P通信带来了...

    基于MFC的UDP打洞通信客户端

    UDP打洞技术是解决NAT(Network Address Translation)环境下对等网络通信的一种方法,它允许两个处于NAT之后的设备直接通信,即使它们不能直接看到对方的IP地址。MFC(Microsoft Foundation Classes)是微软提供的...

    UDP打洞(有心跳包和断网自动连接功能)

    UDP打洞技术是一种在NAT(网络地址转换)环境下实现两个私有网络主机间通信的方法。在互联网上,由于IP地址的稀缺性,许多设备通过NAT与公网交互,这导致了内网设备的IP地址对外不可见。UDP打洞正是为了解决这一问题...

    udp 打洞示例代码 包含服务器 客户端

    UDP打洞技术是一种在NAT(网络地址转换)环境下实现两个私有网络内的主机之间直接通信的方法。在互联网上,许多设备由于连接到ISP时采用了NAT,它们的公网IP实际上是路由器分配的内部IP,因此不能直接与其他网络的...

Global site tag (gtag.js) - Google Analytics