最近一阵子在研究内网穿透,查了很多资料,因此今天就聊聊两种不一样的穿透方式的原理,以及基于java的netty框架的实现,代码也已在个人github。html
原由:忽然花这么大力气研究这个虽然是头脑发热所为,但动机源于跟小伙伴联机打游戏,原来用nat123之类的作远程端口转发在最近一阵子巨慢无比,又没找好的替代方案,前一阵子公司同事又分享过nio,网络编程的知识又被过了遍,一拍脑子本身造轮子得了,正好本身又有个阿里云能够当中间节点,找了些参考文章就开搞了,陆陆续续摸索了三个周末,基本能够用了,这两篇文章就当总结了。java
在通常的网络应用中,简单拓扑模型以下
git
server有公网ip,server应用直接监听公网ip及端口,client访问可直接经过ip:port 直接创建连接,进行请求响应。github
但若是服务端经过路由连接Internet,没有直接暴露公网ip就不一样了,如如下拓扑算法
server在内网,没有公网ip,路由有公网ip,经过路由连接Internet,client请求抵达server路由后,除非在路由定义端口转发规则,不然数据将被抛弃,但不少时候路由的转发规则是没法被改的。编程
这样的模型能够细分为四种状况安全
对于server在公网的状况,client能够主动连接;但server在内网时,咱们便须要内网穿透了。接下文章将以最复杂的第4种状况进行分析。服务器
对于client和server均在内网的状况,直连是不行的,但若是咱们有另一台具备公网ip的服务器充当中间节点,即可以进行间接访问了,拓扑以下网络
中间服务器咱们暂称为forwarder
咱们详细描述下请求响应过程 框架
咱们能够看到内网机器能访问Internet的缘由在于它的路由为其分配了一个随机的公网端口。这里顺带解释概念 端口映射,此时的公网端口12.12.12.12:45464逻辑上能够认为就是内网机器777端口的映射。再抽象一点,对于client来讲,forwarder的666端口其实也能够认为是server 80端口的映射,这个即是远程端口映射,所以,远程端口映射跟内网穿透,描述虽不一样本质上是一致的。
这种模式很是简单直接,只要client和server能连上Internet,就能穿透彼此的内网相互访问。
诸如nat123的端口转发机制,穿透内网的远控软件TeamViewer,咱们玩一些对战游戏的平台,甚至各类网络游戏均可以当作这种模型的实现。
它的优势在于forwarder服务器存在,能够协助穿透任何形式的内网,简单稳定,但一样因为存在中间服务器,网络上不只受客户端网络限制,一样也受forwarder的网络限制,若是forwarder带宽不行,或者传输几g的大文件,效率就慢了。为了解决这个问题,基于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模式的网络拓扑
如下是请求响应过程
P2P方案优势也就明显的,数据传输不依赖于中间服务器,在链接创建后就再也不受其限制,但一样因为UDP的特性,数据可靠性难以保证,因此得容忍偏差,或者实现一些校验机制,并且对于Symmetric NAT,P2P是没法创建的,仍是只能走C/S模式的穿透。
它的应用最普遍的就是各类BT客户端了,毕竟大数据的传输不须要通过中间服务器,效率会高不少,而后一些P2P的聊天,视频,游戏对战软件也能够用到。
至此,两种实现模式的原理已经说明了,下一篇将讲讲基于java netty框架造的两个轮子。
内网穿透并非一个新话题,已经有不少成熟的协议和框架实现了,好比这个,但学习,仍是本身造轮子得好。
做者:chulung
原文连接:https://chulung.com/article/36
本文由MetaCLBlog于2017-02-25 17:39:27自动同步至cnblogs
本文基于 知识共享-署名-非商业性使用-禁止演绎 4.0 国际许可协议发布,转载必须保留署名及连接。
出处:http://www.cnblogs.com/chulung/p/5657073.html