内网穿透原理及实现一:C/S模式,P2P模式原理

1.前言

最近一阵子在研究内网穿透,查了很多资料,因此今天就聊聊两种不一样的穿透方式的原理,以及基于java的netty框架的实现,代码也已在个人github。html

原由:忽然花这么大力气研究这个虽然是头脑发热所为,但动机源于跟小伙伴联机打游戏,原来用nat123之类的作远程端口转发在最近一阵子巨慢无比,又没找好的替代方案,前一阵子公司同事又分享过nio,网络编程的知识又被过了遍,一拍脑子本身造轮子得了,正好本身又有个阿里云能够当中间节点,找了些参考文章就开搞了,陆陆续续摸索了三个周末,基本能够用了,这两篇文章就当总结了。java

2.问题由来

在通常的网络应用中,简单拓扑模型以下
git

server有公网ip,server应用直接监听公网ip及端口,client访问可直接经过ip:port 直接创建连接,进行请求响应。github

但若是服务端经过路由连接Internet,没有直接暴露公网ip就不一样了,如如下拓扑算法

server在内网,没有公网ip,路由有公网ip,经过路由连接Internet,client请求抵达server路由后,除非在路由定义端口转发规则,不然数据将被抛弃,但不少时候路由的转发规则是没法被改的。编程

这样的模型能够细分为四种状况安全

  1. client有公网ip,server在内网;
  2. client在内网,server在公网;
  3. client,server均在公网;
  4. client,server均在内网。

对于server在公网的状况,client能够主动连接;但server在内网时,咱们便须要内网穿透了。接下文章将以最复杂的第4种状况进行分析。服务器

3.内网穿透原理

3.1 基于TCP的C/S模式

对于client和server均在内网的状况,直连是不行的,但若是咱们有另一台具备公网ip的服务器充当中间节点,即可以进行间接访问了,拓扑以下网络

中间服务器咱们暂称为forwarder
咱们详细描述下请求响应过程 框架

  1. client由本机777端口经过路由向forward 11.11.11.11:666发起请求,路由分配公网ip及端口12.12.12.12:45464给client,这里的端口是随机分配的,也就内网机器能够访问Internet应用的缘由。
  2. client连上forwarder后,对应forwarder来讲,它获取到的客户端是12.12.12.12:45464,全部client的777端口的请求都会由路由的45464端口发送给forwarder,同时Forwarder对client的响应实际上是发往路由的45464端口,再由路由转发给client的777端口;
  3. server的80端口经它的路由13.13.13.13:12454也一样与forwarder创建链接;
  4. 这时forwarder只须要将client发送请求数据转发给server的路由12454端口,而后server的响应也经server的路由,发给forwarder,forwarder再转发给client的路由,最后发送至client的777端口,这样就完成了一次穿透两个内网的请求与响应;
  5. 重复过程4,内网穿透也就成功了。

咱们能够看到内网机器能访问Internet的缘由在于它的路由为其分配了一个随机的公网端口。这里顺带解释概念 端口映射,此时的公网端口12.12.12.12:45464逻辑上能够认为就是内网机器777端口的映射。再抽象一点,对于client来讲,forwarder的666端口其实也能够认为是server 80端口的映射,这个即是远程端口映射,所以,远程端口映射跟内网穿透,描述虽不一样本质上是一致的。

这种模式很是简单直接,只要client和server能连上Internet,就能穿透彼此的内网相互访问。
诸如nat123的端口转发机制,穿透内网的远控软件TeamViewer,咱们玩一些对战游戏的平台,甚至各类网络游戏均可以当作这种模型的实现。

它的优势在于forwarder服务器存在,能够协助穿透任何形式的内网,简单稳定,但一样因为存在中间服务器,网络上不只受客户端网络限制,一样也受forwarder的网络限制,若是forwarder带宽不行,或者传输几g的大文件,效率就慢了。为了解决这个问题,基于P2P的机制也就提出来了。

3.2基于UDP的P2P模式

先回头看下C/S模式的网络拓扑

C跟S最终仍是由各自路由随机分配的公网端口进行Internet访问,这样的话,若是它们能彼此知道对方的公网ip和端口,好比经forwarder将ip端口发给对方,是否是就能够直接TCP实现P2P访问呢,答案是比较困难的。

缘由在于TCP是一种先链接后传输的通讯协议,分配给client的45464只能与forwarder的666端口传输数据,这是在链接创建时肯定的,若是client再想连接server的路由,此时的端口将是从新分配的。而且由于安全等问题考虑,端口是随机分配,没法固定。也有一些资料说能够经过某些算法猜想到公网端口从而实现基于TCP的P2P传输,但实现起来比较困难。咱们这里就经过UDP来实现,由于它跟TCP不一样,是在发送数据时指定目标ip端口。

下面来看看基于UDP的P2P模式的网络拓扑

如下是请求响应过程

  1. client开始向forwarder发送请求,因为使用udp,咱们不须要创建链接,路由分配ip,端口后,数据包直接发往forwarder;
  2. forwarder由此能够获得client的公网ip及端口12.12.12.12:45464;
  3. 一样的forwarder获得server的公网ip及端口13.13.13.13:12454;
  4. forwarder将包含server的ip:端口的数据包发给client,将client的发给server;
  5. 因为是UDP,此时client能够直接将包含请求的数据包改成获得的server地址,直接发往server路由,server一样能够直接发给client了。
  6. 双方接受到对方数据后,能够认为一个虚拟的P2P链接就已经创建了, 至此内网穿透便实现了。

P2P方案优势也就明显的,数据传输不依赖于中间服务器,在链接创建后就再也不受其限制,但一样因为UDP的特性,数据可靠性难以保证,因此得容忍偏差,或者实现一些校验机制,并且对于Symmetric NAT,P2P是没法创建的,仍是只能走C/S模式的穿透。

它的应用最普遍的就是各类BT客户端了,毕竟大数据的传输不须要通过中间服务器,效率会高不少,而后一些P2P的聊天,视频,游戏对战软件也能够用到。

至此,两种实现模式的原理已经说明了,下一篇将讲讲基于java netty框架造的两个轮子。

参考文档

内网穿透并非一个新话题,已经有不少成熟的协议和框架实现了,好比这个,但学习,仍是本身造轮子得好。

NAT穿透解决方案介绍

做者:chulung

原文连接:https://chulung.com/article/36

本文由MetaCLBlog于2017-02-25 17:39:27自动同步至cnblogs

本文基于 知识共享-署名-非商业性使用-禁止演绎 4.0 国际许可协议发布,转载必须保留署名及连接。

 

出处:http://www.cnblogs.com/chulung/p/5657073.html

相关文章
相关标签/搜索