NAT原理

 网络地址转换(NAT,Network Address Translation)属接入广域网(WAN)技术,是一种将私有(保留)地址转化为合法IP地址的转换技术。下面介绍两类不同方式实现的NAT:

  1. NAT(Network Address Translators):称为基本的NAT

在客户机时      192.168.0.8:4000——6.7.8.9:8000

在网关时         1.2.3.4:4000——6.7.8.9:8000

服务器C          6.7.8.9:8000

其核心是替换IP地址而不是端口,这会导致192.168.0.8使用4000端口后,192.168.0.9如何处理?具体参考RFC 1631

基本上这种类型的NAT设备已经很少了。或许根本我们就没机会见到。

     2.   NAPT(Network Address/Port Translators):其实这种才是我们常说的 NAT

NAPT的特点是在网关时,会使用网关的 IP,但端口会选择一个和临时会话对应的临时端口。如下图:

在客户机时           192.168.0.8:4000——6.7.8.9:8000

在网关时              1.2.3.4:62000——6.7.8.9:8000

服务器C               6.7.8.9:8000

网关上建立保持了一个1.2.3.4:62000的会话,用于192.168.0.8:4000与6.7.8.9:8000之间的通讯。

对于NAPT,又分了两个大的类型,差别在于,当两个内网用户同时与8000端口通信的处理方式不同:

         2.1、Symmetric NAT型 (对称型)

在客户机时              192.168.0.8:4000——6.7.8.9:8000 192.168.0.8:4000——6.7.8.10:8000

在网关时,两个不同session但端口号不同      1.2.3.4:62000——6.7.8.9:8000 1.2.3.4:62001——6.7.8.10:8000

服务器C      6.7.8.9:8000

服务器 D     6.7.8.10:8000

这种形式会让很多p2p软件失灵。

        2.2、Cone NAT型(圆锥型)

在客户机时              192.168.0.8:4000——6.7.8.9:8000 192.168.0.8:4000——6.7.8.10:8000

在网关时,两个不同session但端口号相同      1.2.3.4:62000——6.7.8.9:8000 1.2.3.4:62000——6.7.8.10:8000

服务器C           6.7.8.9:8000

服务器D           6.7.8.10:8000

目前绝大多数属于这种。Cone NAT又分了3种类型:

  • a)Full Cone NAT(完全圆锥型):从同一私网地址端口192.168.0.8:4000发至公网的所有请求都映射成同一个公网地址端口1.2.3.4:62000 ,192.168.0.8可以收到任意外部主机发到1.2.3.4:62000的数据报。
  • b)Address Restricted Cone NAT (地址限制圆锥型):从同一私网地址端口192.168.0.8:4000发至公网的所有请求都映射成同一个公网地址端口1.2.3.4:62000,只有当内部主机192.168.0.8先给服务器C 6.7.8.9发送一个数据报后,192.168.0.8才能收到6.7.8.9发送到1.2.3.4:62000的数据报。
  • c)Port Restricted Cone NAT(端口限制圆锥型):从同一私网地址端口192.168.0.8:4000发至公网的所有请求都映射成同一个公网地址端口1.2.3.4:62000,只有当内部主机192.168.0.8先向外部主机地址端口6.7.8.9:8000发送一个数据报后,192.168.0.8才能收到6.7.8.9:8000发送到1.2.3.4:62000的数据报。   
  • 穿越NAT的实现

A1在客户机时                192.168.0.8:4000——6.7.8.9:8000

X1在网关时                   1.2.3.4:62000——6.7.8.9:8000

服务器C                       6.7.8.9:8000

B1在客户机时                192.168.1.8:4000——6.7.8.9:8000

Y1在网关时                   1.2.3.5:31000——6.7.8.9:8000

两内网用户要实现通过各自网关的直接呼叫,需要以下过程:

1、 客户机A1、B1顺利通过格子网关访问服务器C ,均没有问题(类似于登录)

2、 服务器C保存了 A1、B1各自在其网关的信息(1.2.3.4:62000、1.2.3.5:31000)没有问题。并可将该信息告知A1、B2。

3、 此时A1发送给B1网关的1.2.3.5:31000是否会被B1收到?答案是基本上不行(除非Y1设置为完全圆锥型,但这种设置非常少),因为Y1上检测到其存活的会话中没有一个的目的IP或端口于1.2.3.4:62000有关而将数据包全部丢弃!

4、 此时要实现A1、B1通过X1、Y1来互访,需要服务器C告诉它们各自在自己的网关上建立“UDP隧道”,即命令A1发送一个 192.168.0.8:4000——1.2.3.5:31000的数据报,B1发送一个192.168.1.8:4000——1.2.3.4:62000的数据报,UDP形式,这样X1、Y1上均存在了IP端口相同的两个不同会话(很显然,这要求网关为Cone NAT型,否则,对称型Symmetric NAT设置网关将导致对不同会话开启了不同端口,而该端口无法为服务器和对方所知,也就没有意义)。

5、 此时A1发给Y1,或者B1发给X1的数据报将不会被丢弃且正确的被对方收到.

综合P2P可实现的条件需要:

1、 中间服务器保存信息、并能发出建立UDP隧道的命令

2、 网关均要求为Cone NAT类型。Symmetric NAT不适合。

3、 完全圆锥型网关可以无需建立udp隧道,但这种情况非常少,要求双方均为这种类型网关的更少。

4、 假如X1网关为Symmetric NAT, Y1为Address Restricted Cone NAT 或Full Cone NAT型网关,各自建立隧道后,A1可通过X1发送数据报给Y1到B1(因为Y1最多只进行IP级别的甄别),但B2发送给X1的将会被丢弃(因为发送来的数据报中端口与X1上存在会话的端口不一致,虽然IP地址一致),所以同样没有什么意义。

5、 假如双方均为Symmetric NAT的情形,新开了端口,对方可以在不知道的情况下尝试猜解,也可以达到目的,但这种情形成功率很低,且带来额外的系统开支,不是个好的解决办法。

6、 不同网关型设置的差异在于,对内会采用替换IP的方式、使用不同端口不同会话的方式,使用相同端口不同会话的方式;对外会采用什么都不限制、限制IP地址、限制IP地址及端口。

7、 这里还没有考虑同一内网不同用户同时访问同一服务器的情形,如果此时网关采用AddressRestricted Cone NAT 或Full Cone NAT型,有可能导致不同用户客户端可收到别人的数据包,这显然是不合适的。

 UDP和TCP打洞

为什么网上讲到的P2P打洞基本上都是基于UDP协议的打洞?难道TCP不可能打洞?还是TCP打洞难于实现?
    假设现在有内网客户端A和内网客户端B,有公网服务端S。
    如果A和B想要进行UDP通信,则必须穿透双方的NAT路由。假设为NAT-A和NAT-B。
    
    A发送数据包到公网S,B发送数据包到公网S,则S分别得到了A和B的公网IP,
S也和A B 分别建立了会话,由S发到NAT-A的数据包会被NAT-A直接转发给A,
由S发到NAT-B的数据包会被NAT-B直接转发给B,除了S发出的数据包之外的则会被丢弃。
所以:现在A B 都能分别和S进行全双工通讯了,但是A B之间还不能直接通讯。

    解决办法是:A向B的公网IP发送一个数据包,则NAT-A能接收来自NAT-B的数据包
并转发给A了(即B现在能访问A了);再由S命令B向A的公网IP发送一个数据包,则
NAT-B能接收来自NAT-A的数据包并转发给B了(即A现在能访问B了)。

以上就是“打洞”的原理。

为了保证A的路由器有与B的session,A要定时与B做心跳包,同样,B也要定时与A做心跳,这样,双方的通信通道都是通的,就可以进行任意的通信了。

    但是TCP和UDP在打洞上却有点不同。这是因为伯克利socket(标准socket规范)的
API造成的。
    UDP的socket允许多个socket绑定到同一个本地端口,而TCP的socket则不允许。
    这是这样一个意思:A B要连接到S,肯定首先A B双方都会在本地创建一个socket,
去连接S上的socket。创建一个socket必然会绑定一个本地端口(就算应用程序里面没写
端口,实际上也是绑定了的,至少java确实如此),假设为8888,这样A和B才分别建立了到
S的通信信道。接下来就需要打洞了,打洞则需要A和B分别发送数据包到对方的公网IP。但是
问题就在这里:因为NAT设备是根据端口号来确定session,如果是UDP的socket,A B可以
分别再创建socket,然后将socket绑定到8888,这样打洞就成功了。但是如果是TCP的
socket,则不能再创建socket并绑定到8888了,这样打洞就无法成功。

UDP打洞的过程大致如此: 

1、双方都通过UDP与服务器通讯后,网关默认就是做了一个外网IP和端口号 与你内网IP与端口号的映射,这个无需设置的,服务器也不需要知道客户的真正内网IP 

2、用户A先通过服务器知道用户B的外网地址与端口  

3、用户A向用户B的外网地址与端口发送消息,  

4、在这一次发送中,用户B的网关会拒收这条消息,因为它的映射中并没有这条规则。  

5、但是用户A的网关就会增加了一条允许规则,允许接收从B发送过来的消息  

6、服务器要求用户B发送一个消息到用户A的外网IP与端口号  

7、用户B发送一条消息,这时用户A就可以接收到B的消息,而且网关B也增加了允许规则  

8、之后,由于网关A与网关B都增加了允许规则,所以A与B都可以向对方的外网IP和端口号发送消息。



TCP打洞技术:
tcp打洞也需要NAT设备支持才行。
tcp的打洞流程和udp的基本一样,但tcp的api决定了tcp打洞的实现过程和udp不一样。
tcp按cs方式工作,一个端口只能用来connect或listen,所以需要使用端口重用,才能利用本地nat的端口映射关系。(设置SO_REUSEADDR,在支持SO_REUSEPORT的系统上,要设置这两个参数。)

连接过程:(以udp打洞的第2种情况为例(典型情况))
nat后的两个peer,A和B,A和B都bind自己listen的端口,向对方发起连接(connect),即使用相同的端口同时连接和等待连接。因为A和B发出连接的顺序有时间差,假设A的syn包到达B的nat时,B的syn包还没有发出,那么B的nat映射还没有建立,会导致A的连接请求失败(连接失败或无法连接,如果nat返回RST或者icmp差错,api上可能表现为被RST;有些nat不返回信息直接丢弃syn包(反而更好)),(应用程序发现失败时,不能关闭socket,closesocket()可能会导致NAT删除端口映射;隔一段时间(1-2s)后未连接还要继续尝试);但后发B的syn包在到达A的nat时,由于A的nat已经建立的映射关系,B的syn包会通过A的nat,被nat转给A的listen端口,从而进去三次握手,完成tcp连接。

从应用程序角度看,连接成功的过程可能有两种不同表现:(以上述假设过程为例)
1、连接建立成功表现为A的connect返回成功。即A端以TCP的同时打开流程完成连接。
2、A端通过listen的端口完成和B的握手,而connect尝试持续失败,应用程序通过accept获取到连接,最终放弃connect(这时可closesocket(conn_fd))。
多数Linux和Windows的协议栈表现为第2种。

但有一个问题是,建立连接的client端,其connect绑定的端口号就是主机listen的端口号,或许这个peer后续还会有更多的这种socket。虽然理论上说,socket是一个五元组,端口号是一个逻辑数字,传输层能够因为五元组的不同而区分开这些socket,但是是否存在实际上的异常,还有待更多观察。

另外的问题:
1、Windows XP SP2操作系统之前的主机,这些主机不能正确处理TCP同时开启,或者TCP套接字不支持SO_REUSEADDR的参数。需要让AB有序的发起连接才可能完成。

上述tcp连接过程,仅对NAT1、2、3有效,对NAT4(对称型)无效。
由于对称型nat通常采用规律的外部端口分配方法,对于nat4的打洞,可以采用端口预测的方式进行尝试。


一些现在常用的技术:

ALG(应用层网关):它可以是一个设备或插件,用于支持SIP协议,主要类似与在网关上专门开辟一个通道,用于建立内网与外网的连接,也就是说,这是一种定制的网关。更多只适用于使用他们的应用群体内部之间。

UpnP:它是让网关设备在进行工作时寻找一个全球共享的可路由IP来作为通道,这样避免端口造成的影响。要求设备支持且开启upnp功能,但大部分时候,这些功能处于安全考虑,是被关闭的。即时开启,实际应用效果还没经过测试。

STUN(Simple Traversalof UDP Through Network):这种方式即是类似于我们上面举例中服务器C的处理方式。也是目前普遍采用的方式。但具体实现要比我们描述的复杂许多,光是做网关Nat类型判断就由许多工作,RFC3489中详细描述了。

TURN(Traveral Using Relay NAT):该方式是将所有的数据交换都经由服务器来完成,这样NAT将没有障碍,但服务器的负载、丢包、延迟性就是很大的问题。目前很多游戏均采用该方式避开NAT的问题。这种方式不叫p2p。

ICE(Interactive Connectivity Establishment):是对上述各种技术的综合,但明显带来了复杂性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/444738.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

推荐系统(2)-协同过滤1-UserCF、ItemCF

协同过滤1.CF概述2.数据表示3.衡量相似度4.共现矩阵5.UserCF6.ItemCF7.UserCF 与ItemCF 应用场景、主要缺陷8.基于UserCF 电影推荐demo《深度学习/推荐系统》读书笔记推荐系统的发展一日千里 传统的推荐模型(2010年前后):协同过滤、罗辑回归、因子分解、梯度提升树 …

sql查询实例1(学生表_课程表_成绩表_教师表)

表架构 Student(S#,Sname,Sage,Ssex) 学生表 Course(C#,Cname,T#) 课程表 SC(S#,C#,score) 成绩表 Teacher(T#,Tname) 教师表 建表语句 CREATE TABLE student ( s# INT, sname nvarchar(32), sage INT, ssex nvarchar(8) ) CREATE TABLE course ( c# INT, cname…

android 存储方式以及路径简介

存储分成了内部存储和外部存储。注意内部存储又叫做机身内存,而且内存又包含了两个部分RAM(运行时内存,这个和运行速度有关系,是手机运行时存储数据和指令的地方)、ROM(这个才算是真正存储东西的内部存储范围,是应用配置和其他数据的地方);而外部存储就很明确了,用户的外部挂…

MachineLearning(11)-关联规则分析

关联规则分析1.简单来说-关联规则2.经典关联规则挖掘-Apriori1.简单来说-关联规则 关联规则–通过量化的数字描述物品甲的出现 对 物品乙的出现 有多大影响。 最早是为了发现超市销售数据库中不同的商品之间的关联关系:哪组商品可能会在一次购物中同时购买。 广泛…

APK 安卓反编译

在学习Android开发的过程你,你往往会去借鉴别人的应用是怎么开发的,那些漂亮的动画和精致的布局可能会让你爱不释手,作为一个开发者,你可能会很想知道这些效果界面是怎么去实现的,这时,你便可以对改应用的A…

sql查询实例2(借书卡、图书、借书记录)

问题描述: 本题用到下面三个关系表: CARD 借书卡。 CNO 卡号,NAME 姓名,CLASS 班级 BOOKS 图书。 BNO 书号,BNAME 书名,AUTHOR 作者,PRICE 单价,QUANTITY 库存册数 BORROW 借书记录。 CNO 借…

开始学习Unity3D(一)

本人最近转行开始做海外独立游戏的发行,主要是负责服务器,开会注意到海外的服务越来越丰富越来越细分,对国内将会造成很大的冲击,比如AWS,Google,GameSparks等,这导致国内的所谓服务器开发将越来越简单,国内对服务器开发的需求越来越少,反而客户端的需求越来越多,所以…

List 流的使用

摘要 本文将介绍在 Java 1.8 中对 List 进行流操作的使用方法。引入的 java.util.stream 包为开发者提供了一种更为便捷和强大的方式来处理集合数据。通过使用流,我们能够以声明性的方式进行集合操作,减少了样板代码,提高了代码的可读性和可…

推荐系统(3)-协同过滤2-矩阵分解算法

协同过滤-矩阵分解算法1.奇异值分解2.梯度下降3.矩阵分解方法的优缺点《深度学习/推荐系统》读书笔记(其实矩阵分解和协同过滤已经没有特别大的联系了) 2006年,在Netfilx举办的推荐算法竞赛中Netflix Prize Challenge中,以矩阵分解…

leetcode141 环形链表

给定一个链表,判断链表中是否有环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。 示例 1: 输入:head …

iPhoneX适配

目录(?)[-]核心代码自动化修改代码参考资料iPhoneX适配,比较搓的一种方式,在不修改分辨率(720 x 1280)的情况下适配iphone X 主屏尺寸: 5.8英寸 主屏分辨率: 2436 x 1125核心代码修改 工程目录/Classes/Un…

centos安装nginx,配置负载均衡

1、安装nginx安装教程,参照:http://mp.weixin.qq.com/s/RVaRlRpHqZRjCaXGmOlfKw 2、反向代理的配置修改部署目录下conf子目录的nginx.conf文件的内容[html]view plaincopylocation / { #设置主机头和客户端真实地…

leetcode142 环形链表II

给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有…

PaperNotes(18)-VectorNet- Encoding HD Maps and Agent Dynamics from Vectorized Representation

自动驾驶论文阅读笔记11. Ployline Garph2. Global Graph3. 模型目标函数4.Related work5.Experiment5.1 实验设置5.2 消融实验5.3 模型资源消耗5.4 与其他模型的对比实验VectorNet- Encoding HD Maps and Agent Dynamics from Vectorized RepresentationVectorNet: 通过矢量化…

ubuntu的apache配置https

一、配置Apache 1、开启SSL模块a2enmod ssl 2、启用SSL站点a2ensite default-ssl 3、加入监听端口vi /etc/apache2/ports.conf #编辑Apache端口配置,加入443端口 Listen 443注:Ubuntu启用SSL站点后,缺省已经加入了 (…

vim特别好的教程

欢 迎 阅 读 《 V I M 教 程 》 —— 版本 1.7 Vim 是一个具有很多命令的功能非常强大的编辑器。限于篇幅,在本教程当中 就不详细介绍了。本教程的设计目标是讲述一些必要的基本命令,而掌握好这 些命令&#x…

jquery、javascript实现(get、post两种方式)跨域解决方法

&#xfeff;&#xfeff;jquery、javascript实现(get、post两种方式)跨域解决方法一、实现get方式跨域请求数据浏览器端<script> $(document).ready(function(){$.ajax({url: "http://www.xxx.cn/index.php",type: "get",dataType: "jsonp&quo…

推荐系统(4)-逻辑回归LR、POLY2、FM、FFM

逻辑回归LR、POLY2、FM、FFM1.逻辑回归LR2.辛普森悖论3.POLY24.FM-20105.FFM6.GBDTLR-20147.LS-PLM-2017《深度学习/推荐系统》读书笔记1.逻辑回归LR Logistic Regression – 融合多种特征&#xff0c;通过sigmoid 函数&#xff0c;预测样本的被点击的概率。样本用特征向量x[x…

leetcode125验证回文串

给定一个字符串&#xff0c;验证它是否是回文串&#xff0c;只考虑字母和数字字符&#xff0c;可以忽略字母的大小写。 说明&#xff1a;本题中&#xff0c;我们将空字符串定义为有效的回文串。 示例 1: 输入: "A man, a plan, a canal: Panama" 输出: true 示例 …

配置 Elastic Beanstalk 环境负载均衡器以终止 HTTPS

&#xfeff;&#xfeff;配置 Elastic Beanstalk 环境负载均衡器以终止 HTTPS 要更新您的 AWS Elastic Beanstalk 环境以使用 HTTPS&#xff0c;您需要为您的环境中的负载均衡器配置 HTTPS 侦听器。以下两种类型的负载均衡器支持 HTTPS 侦听器&#xff1a;传统负载均衡器和应用…