最近工作中有公网访问内网服务的需求,便了解了内网穿透相关的知识。发现原理和实现都不复杂,遂产生了设计一个内网穿透的想法。
名字想好了,就叫QuantumTunnel
,量子隧道,名字来源于量子纠缠现象。
两个处于量子纠缠的粒子,无论处于多么远的距离,当其中一个粒子状态改变时,另外一个粒子也会做出相应的改变。
QuantumTunnel也取意于此,希望把公网发出来的请求,完整的同步到内网,就像在内网发出的请求,打破网络的限制。
什么是内网穿透?摘自百度百科
内网穿透,也即 NAT 穿透,进行 NAT 穿透是为了使具有某一个特定源 IP 地址和源端口号的数据包不被 NAT 设备屏蔽而正确路由到内网主机。
通俗易懂一点就是一个公网内的机器与不能被公网访问的机器进行数据交换。
这个不能被公网访问的机器有可能在某个机房,也有可能在家。
归纳总结一下。为了实现内网穿透能力,内网穿透服务中应该有的几个角色:
用户服务器
:处理用户过来的请求,将用户请求转发给代理服务器;代理服务器
:接收用户服务器过来的请求数据并转发给往代理客户端;接收代理客户端的结果数据并返回给用户服务器;代理客户端
:接收代理服务器的请求数据并且进行真正的请求,拿到结果数据后返回给代理服务器。按照上述思路,内网穿透的架构应该是这样的:
我们再次梳理一下参与到内网穿透服务的各个角色:
顺着这个思路,我们来画一下时序图。
时序图分为两部分:
首先,代理服务器和代理客户端建立了一条长连接
,用于数据的传输,这个很关键。
因为代理服务器(公网)无法直接访问代理客户端,必须由代理客户端主动向代理服务器发起连接请求,从而建立一条可以双向通信的连接通道,利用双向通信的能力实现代理服务器主动向代理客户端发送请求的能力
然后是一次内网穿透请求的流程。
要注意的是对raw request(response)的处理:raw request -> proxy request ->; raw request,经历了从原始请求到代理请求再到原始请求的封装和解析过程。
为什么要有这个协议转换过程?要实现协议无侵入(如http、ws)的目标,只能在现有协议上扩展请求。如内网穿透http协议,可以把目标地址和目标端口放在header中进行扩展,内网穿透-用户服务器再把相关的参数给解析出来,从而知道目标地址和端口是什么。这样处理的好处也显而易见,在原来的框架、代码不变的情况下,增加几个参数就可以用上内网穿透服务。
大家可以了解一下这两个内网穿透的实现,natx和毒刺,我在设计实现过程中参考了他们的一些实现。
结合上面的架构图、时序图,要想实现应用层协议无侵入,需要一个能直接在传输层进行流量代理的工具。在网络传输领域大火的netty便进入了我们的视线,支持TCP、UDP流量转发,拥有丰富的应用层协议插件,更重要的是发送数据非常方便,只需要往Channel里面写入数据就行。
对于具体实现,本文暂不讨论,计划放在QuantumTunnel系列博客中的第二篇展开。
下面看看实现的效果。
假设南京本地宝的服务器在内网,我们现在要访问它的新闻咨询频道。原始链接为:http://nj.bendibao.com/news/
把目标服务器替换成南京本地宝服务器,重新画一下架构图和时序图:
从返回的结果可以看到,通过本地的8090端口,访问到了南京本地宝的服务器,说明整个链路成功走通。
这里解释一下访问结果中的几个参数
proxyHost:被代理的服务器地址;proxyPort:被代理的服务器端口
好了,本篇就聊到这里。后面会推出一个系列博客聊一下基于Netty的实现方案,以及业务隔离、服务高可用的一个探索等好玩的东西。