基于Netty的网络编程学习之网络穿透实践

基于Netty的网络编程学习之网络穿透实践

1.什么是网络编程?

网络编程通俗的讲就是将自来水厂的水输送到千家万户,在输送过程中按照规定好的水管路线,将水准确无误的送达指定的地点,在这里水厂类比服务端,水龙头类比客户端,但实际的网络编程比这还要复杂,由于在计算机通信中,是以网络为载体,以字节形式描述数据,且由于TCP网络协议的约束,数据在发送过程中往往不是按照用户指定的容量数据传输,这就会产生粘包、拆包现象,并且由于字节不便于我们编程开发理解业务,往往又要涉及编码、解码的操作。简而言之就是客户端与服务端按照某种约定协议进行网络通信,将数据从一端发往另一端,保证数据的完整接收,实现双向通信。

2.网络编程如何技术选型?

在这里只谈论JAVA领域开发, 基于网络编程,Java提供了三种开发模式:
1. BIO,同步阻塞式IO,简单理解:一个连接一个线程
2. NIO,同步非阻塞IO,简单理解:一个请求一个线程
3. AIO,异步非阻塞IO,简单理解:一个有效请求一个线程

点击查看BIO/NIO/AIO详细介绍

可以根据你的业务进行选型。如果你不想使用JDK自带的开发组件,可以尝试考虑Apache出品的Mina或者IBM出品的Netty。

3.你为什么要开发Pandora-Passthrough,它能干什么事情?

开发是由于需求的萌生,之前在开发微信,支付宝支付 ,还有两台路由器网络不通,或者网线通,wifi不通等由于网络NAT的原因 ,无法收到通知回调,虽然可以在线上服务器使用 ,但是调试过于麻烦,后来尝试路由器外网映射,由于国内网络原因,没有公网IP,导致开发非常麻烦,后来尝试采取使用花生壳,虽然能用,但诸多限制,很不方便,也曾使用Ngork,Frp等工具,但是感觉不方便,恰好想学习网络编程技术,于是动手开发。
它能干什么事情取决你自己有多大的创意,一支笔能画画 ,能写诗,能绕圈。 在这里大概说下。如果你的网络可以访问互联网,但是别人无法直接访问你的服务,你可以借助他完成这项事情。分享下我做的事情:
  1. 远程控制家里电脑,配合智能开关,远程开关机电脑,远程执行任务,出门在外也可以获取电脑的信息服务
  2. 暴漏自己的Web服务,在手机里启动一个Http服务,出门在外随时随地访问。手机如何启动服务,请参考
    点击查看 安卓手机做服务器
  3. 各种需要异步应答通知的第三方服务,支付宝,微信当然少不了。
  4. 由于公司多台路由器不通,公司网络的复杂性,或者需要模拟真实外网环境测试,当然一马当先。
  5. 将程序内置在路由器里,你家的网络,随时随地可以访问。
  6. 更多使用场景,期待你的发现。

4. 可以介绍下你的开发思路,程序实现原理吗?

当然可以,我很乐意分享这一神秘背后的秘密。当然说他神秘,主要还是作为使用者,感受的莫名强大,揭开真实的面目,其实很简单。在这里 分享下我画的结构图 。

内外网穿透示意图.png

如果你是 一名开发者,请查看我的项目代码,地址是:https://github.com/yancheng199287/Pandora-Passthrough
项目结构分为,客户端,协议,服务端。其中客户端是安装用户在本地的,服务端是安装在公网服务器上的,协议部分负责帮助二者进行有效完整的通信。

5. 可以谈谈你在使用Netty的感受或者经验之谈吗?

是的,可以的。我从萌生想法到实践完成总共花了近三个月,大多数还是业余挤出来的时间,其中包括入门学习到实战开发还有不断的调试工作。首先学习Netty,你可以加下QQ群:368512253 ,我会分享一些学习资料之类的。我大概有两本资料文档,另外参考官方文档DEMO学习的。有些人喜欢别人视频一步步讲解,当然有人讲解 细致肯定很好的,但是实际上市面上很少有类似视频教程,哪怕是有也是很粗浅的,可能你看完了还是不会,我们 学习开发一定要多实践。首先,看介绍文档,结构组成,粗略看下,即使很多不懂没关系,再去官网看Demo,Netty的项目地址有 很多案例,都可以作为参考,有些不懂的可以实际编码测试,看是否达到预期效果,实际上Netty是非常强大的,几乎屏蔽了所有复杂的事情,如果你比较了解,开发起来还是很快的。如果你时间不多,请不要一直测试证明问题,不妨直接看源码doc或者相关博文,在一些概念基础上去 做进一步测试,可能 更快,思路更多。

6. 说说你在项目开发中遇到的问题吧

其实有很多问题,刚开始学习Netty,做了一个简单的反向代理,主要是有前端朋友提出想做跨域访问。如果利用Netty框架现有的基础辅助类,可以非常轻松完成,你所担心的编解码工作都有现成的,比如请求解码,响应编码,消息聚合,消息压缩等常用编解码器。实际上在Netty中编解码是非常重要的,它对你的数据传输起到决定性作用,如果你的编解码器写好了,就成功一半了。 从上面结构图可以看到,实际程序内部 有两个 服务端,有两个客户端,如何把他们联合起来,把 数据进行有效传输是 一个比较麻烦的事情,这种事情就落在编解码上。开始,我想利用现成的Htpp相关编解码器去搞定,我 就不关注协议,拆包,粘包的事情,但是这样行不通,因为有时候 的请求 消息可能 需要编码,也可能需要解码 ,响应同样如此,现有的无法满足,并且最大问题就是 这套程序的使用范围 就太窄了,说到这里,很有幸一个大神朋友告诉的一句话,程序不要管协议上的事情,只需要桥接好开始进口和最终出口,为他们提供一个通信机制就可以 了,因为协议上的事情最开始的真实客户端,和最终真实的服务端会去处理,如果你使用Http编解码器,那你就 只能使用Web服务了。显然这不是我的需求。于是全部 删除,再来。由于程序 有一些业务规则,最简单就是访问认证。于是需要定制自己的编解码器。
关于编解码器有很多,下面是一些常用解决粘包拆包的编解码器:
  1. 基于定长的 FixdLengthFrameDecoder
  2. 基于分隔符的 DelimiterBaseFrameDecoder
  3. 基于回车换行符的 LineBasedFrameDecoder
  4. 基于长度区域的 LengthFieldBasedFrameDecoder
本项目中使用的第四种,简单使用,强大方便。
在Netty中每个激活的通道可以保存起来,每个通道有个唯一id标识, 在服务端发送请求消息后,需要告诉客户端是哪个通道请求的,因为客户端响应的时候也必须是这个通道去写响应消息,因此我们自定义协议在通信来往过程中可以准确从缓存中取出对应的通道。
在测试发现 一个问题, 浏览器多次刷新,会出现一个 通道 发送两次包,而这个请求必须是两个完整的包合并,注意如果你前面没有解码器, 在channelRead0方法里 直接拿走请求 消息是很危险的,因为消息可能是截取几半发送 的,为了解决 这个问题,我们要知道通一个通道多次读取的 消息仍然 是这个handler的实例,我们只需要去合并字节,在调用channelReadComplete方法 时候认为这个包 读取完毕,然后开始发送。
由于服务端有个代理客户端需要多次请求YCServer端,访问一个网站,涉及JS,CSS,IMG,HTML等大量的请求,导致通道急剧膨胀,如果不及时清理,会导致通道浪费,端口浪费,资源浪费,为此我们加入了心跳IdleStateHandler,在超时未读写 的时候我们去关闭释放通道。
我的项目中,涉及有短连接也有长连接,涉及通道缓存,自定义协议,心跳检测,消息合并,代理请求等相关技术,如果你需要,不妨研究学习下 。 如果你需要他给你提供服务,不妨可以下载下来使用,有任何问题 可以与我联系,以便改进。如果你觉得还可以,不妨为我点颗星。
 Java高级面试题BAT面试宝典薪资提高秘籍武器
MySQL主从复制原理实现过程 
上一篇:Java高级面试题BAT面试宝典薪资提高秘籍武器
下一篇:MySQL主从复制原理实现过程
评论

如果我的文章对你有帮助,或许可以打赏一下呀!

支付宝
微信
QQ