目前流行的网站开发技术,西安道桥建设有限公司网站,网页设计尺寸大小,得实网站建设爷的开场白
掘金的朋友们大家好#xff01;我是新来的Java练习生 CodeCodeBond#xff01; 这段时间呢#xff0c;博主在学习Netty#xff0c;想做一个自己感兴趣好玩的东西#xff0c;那就是内网穿透#xff01;#xff01;#xff08;已经实现主要代理功能但有待优化…爷的开场白
掘金的朋友们大家好我是新来的Java练习生 CodeCodeBond 这段时间呢博主在学习Netty想做一个自己感兴趣好玩的东西那就是内网穿透已经实现主要代理功能但有待优化 后面会介绍到我个人的一些思路能把学校内网的电控系统穿出来玩玩嘿嘿嘿 老实求放过说明 博主对Netty底层知识仅仅是了解一下皮毛哈哈哈精巧的框架让像我这种黄毛小子短时间熟悉精通确实不是那么容易的需要时间的沉淀#沉淀 orz 什么连Netty的底层知识都不懂居然还会用Netty做开发网络编程我想这也是框架的意义所在吧将复杂繁琐的底层封装成简单好用且高性能的API让开发者快速上手。大多数Java混子curdBoy不也不知道Spring框架, Mysql的底层么…os:真是自己骂自己
简单聊聊我眼中Netty是什么
Netty是一个优雅著称的高性能网络编程框架 用于快速开发可维护的高性能协议服务器和客户端。Netty被广泛应用于各类网络应用开发尤其是需要高性能和低延迟的场景如游戏服务器、各种中间件和分布式系统等等。
Netty在我的眼里 是Java领域内高性能网络编程的基石。 在网络编程的地位非常之高有多高呢有三四百层楼那么高吧。
可能身边的同学们还在用各种RPC、MQ…ES的时候还不知道Netty在里面吧一种精通…咳咳了解Netty的快感油然而生~
没错我们熟知的Dubbogrpc的java端rocket mq等等底层都有Netty的相关实现。Spring的web相关组件也是大量用到Netty比如webFlux等。足以说明Netty的地位。
我认为Netty有两大特点异步和回调。这使得Netty在高并发下仍能保持良好的性能以及处理各种事件。
问题来了不熟悉网络编程的我在一开始上手十分困难异步的机制和回调的代码书写让我感到十分难受后来越来越被这种特点着迷实际上Netty异步回调的代码实现的非常优雅。
它大量用到前人总结的设计模式例如handler处理时候自定义的责任链模式回调函数Listener的观察者模式… 真正的让开发者自由扩展优雅编程。
下面我来简单说说Netty开发时的常用组件
常用组件
EventLoop事件循环对象
EventLoop 本质是一个单线程执行器同时维护了一个Selector里面有run方法处理Channel上源源不断地io事件。
它有两条继承线
1、java并发包下的 j.u.c.ScheduledExecutorService 包含所有线程池的方法
2、Netty自身OrderedEventExecutor
提供了 isEventLoop(Thread thread) 方法判断这个线程是否属于它
提供了parent方法 来看自己属于哪个EventLoopGroup
EventLoopGroup (事件循环组)
事件循环组
eventloopgroup是一组eventloop,channel一般会调用eventloopgroup的register方法来绑定其中一个
eventloop,后续这个hannel 上的10事件都由此eventloop来处理保证了io事件处理时的线程安全
继承自 netty 自己的 ececutorgroup
实现了 iterable接口提供遍历 eventloop的 的能力
另有next 方法获取集合中下一个eventloop ps: 其实一般开发就用两个如果是接收多端的服务端ServerBootstrap那就一个BossGroup一个WorkerGroupboss处理accept连接而worker则处理io事件。如果是连接一个服务端的客户端那么就只需要一个worker就可以啦 Channel
channel的主要作用及其常用函数
close()可以用来关闭channel
closefuture0用来处理channel的关闭
sync方法作用是同步等待channel关闭
而ad addlistener 方法是异步等待channel 关闭
pipeline()方法添加处理器(自定义处理器编解码处理器等等Idle保活等等)
write()方法将数据写入
writeandflush0方法将数据写入并刷出
Future
搭配Promise既可以同步也可以异步可以用的十分丰富炫酷可以搭配juc去配套食用理解。
EmbeddedChannle
一般用来测试自己的处理器很方便可以直接将数据刷入站读入站的数据。出站同理。 我就用来测试自己消息传输协议的编解码器很方便的。 ByteBuf
池化与非池化 减少建立连接的开销直接内存与堆内存直接内存读写快堆内存分配快相辅相成自动扩容机制 每次检测是否够空间()- 不够 { 小于512直接扩容到512 如果大于512都是*2处理 }
没错仅需要这些组件还有一些Handler要知道就可以开始愉快的网络编程了。起飞~
我认为Netty能干嘛
掌握了这些我能做什么。掌握了这些你可以自由开发你能想到的网络编程甚至是做一个服务器去代替Tomcat咳咳我相信有部分公司应该是不用tomcat的…吧精通了Netty那真的是非常之牛掰了真正的掌握JUC、NIO、Socket编程的王Orz
比如能干嘛呢 比如你可以基于Netty可以实现简单的聊天室功能了被写烂了参考某马程序员的Netty课程。如果要实现的比较正式高级的聊天室可以到某站搜索程序员老罗 他的仿微信项目中的聊天业务使用的Netty比较好开源精神o(▽)
我对内网穿透比较有兴趣所以我学完Netty的基础后捏就快速的上手手搓了一个简单的内网穿透项目嗨嗨嗨
等我完善好哈我一定要开源出来做到简单配置简单使用简单扩展覆盖大多数人的需求。/加油xdm双击点波关注上车了喂
我的内网穿透分析
下面是我实现内网穿透的思路 有更好的思路欢迎讨论一起交流进步
概括起来 其实主要分为三步
1、 自定义消息传输协议 protocol。消息类包括typedata…当然还要有编解码器。
2、 监听访客端 代理服务端 代理客户端 内网服务端。 四端以及他们的对应的自定义Handler。
3、 设计什么时候建立什么通道什么时候用什么通道发送数据什么时候关闭通道。并且如何维护这条通道不会乱窜。
一、自定义消息传输协议
既然是协议那肯定有消息体有编解码。
首先ProxyMsg这个类你可以随便造最简单的必须要有的也就是type和data两个属性其他消息流水号、指令消息等等可以自由发挥~ 这里是一个PeoxyMsg示例
Data
EqualsAndHashCode
public class ProxyMsg {/** 心跳 */public static final byte TYPE_HEARTBEAT 0x00;/** 数据传输 */public static final byte TYPE_TRANSFER 0x01;/** 连接 */public static final byte TYPE_CONNECT 0x10;/** 连接断开 */public static final byte TYPE_DISCONNECT 0x11;//-----------------------------------------------------/** 消息类型 */private byte type;/** 消息携带数据 */private byte[] data;}因为Netty是基于字节流的ByteBuf数据传输时自然会有粘包、半包的问题。所以编解码器要去解决这个问题。ProxyMsgEncoder和ProxyMsgDecoder。 如何去解决粘包问题呢 Netty提供了一个解决方案使用LengthFieldBasedFrameDecoder实现定长解码器通过定义一条消息的各部分的实际长度控制解码读取字节的时候不多读不少读按照规定字段长度读 这里提供同样也提供一个ProxyMsgDecoder的示例哈
Slf4j
public class ProxyMsgDecoder extends LengthFieldBasedFrameDecoder {public ProxyMsgDecoder(){super(Integer.MAX_VALUE, 0, 4, 0, 0);}Overrideprotected ProxyMsg decode(ChannelHandlerContext ctx, ByteBuf in2) throws Exception {ByteBuf in (ByteBuf) super.decode(ctx, in2);log.info(in:{},in);if(innull||in.readableBytes()4){return null;}int dataLen in.readInt();byte type in.readByte();ProxyMsg msg new ProxyMsg();msg.setType(type);if(dataLen1){byte[] data new byte[dataLen - 1];in.readBytes(data);msg.setData(data);}
// log.info(msg:{},msg);in.release();return msg;}
}既然消息的解码器你已经想好了将ByteBuf进行编码成ProxyMsg就很简单了这里是ProxyEncoder类示例
Slf4j
public class ProxyMsgEncoder extends MessageToByteEncoderProxyMsg {//提供空参构造public ProxyMsgEncoder(){}Overrideprotected void encode(ChannelHandlerContext ctx, ProxyMsg msg, ByteBuf out) throws Exception {
// log.info(msg encode:{},msg);int bodyLen 1; //一个字节表示类型长度嘛这个必须有的if(msg.getData() ! null){bodyLen msg.getData().length;}//先写入消息体长度 单位字节out.writeInt(bodyLen);//写入消息体类型out.writeByte(msg.getType());//写入消息携带的dataif (msg.getData() ! null) {out.writeBytes(msg.getData());}}
}ok这样就做好了最简单的消息协议了是不是发现协议其实也就是一种约定罢了但是真正的协议其实要复杂的多。这里就不赘述了 O.o
用刚刚说到的EmbeddedChannel来测试一下吧
public class Test {public static void main(String[] args) {EmbeddedChannel channel new EmbeddedChannel();ProxyMsg msg new ProxyMsg();msg.setType(ProxyMsg.TYPE_HEARTBEAT);msg.setData(11111.getBytes());channel.pipeline().addLast(new ProxyMsgDecoder()).addLast(new ProxyMsgEncoder());channel.writeOutbound(msg);ByteBuf encodedMsg channel.readOutbound();channel.writeInbound(encodedMsg);ProxyMsg decodedMsg channel.readInbound();System.out.println(Type: decodedMsg.getType());System.out.println(Data: new String(decodedMsg.getData()));System.out.println(0x10);}
}测试结果不出所料没错日志打出来的就是我们想要的嘛。
直到这里我们真正的建立好了简单的消息传输协议可以开始着手做Socket的开发了。
二、我选择设计四个Socket
我将按照访客 代理服务端 代理客户端 内网服务; 这样的顺序来讲 反之同理 首先我觉得有必要说一下启动的流程: 是 先把代理两端也就是Netty做的代理服务端和客户端启动并相连接当客户端连接上服务端后建立一条客户端Connect.addListener()发送一条TYPE_CONNECT的消息服务端收到解析后注册这条主通道。 注册好主通道后启动访客端监听公网某某端口接收访客的请求数据。当有访客连接建立访客通道 启动内网服务端connect.addListener()连接成功的话就建立起内网服务真实通道。 因为Netty是异步的每个启动中的步骤他都是一起执行的。所以这些操作只需要注意启动的顺序就可以了,代理服务器启动- 代理客户端- 内网服务端访客端启动 以下是实现的端口以及handler的分析
内网服务Socket\代理客户端 : Bootstrap 访客代理Socket\代理服务端 : ServerBootstrap 为什么呢 其实判断他是单端的还是多端的就会明白
VisitorSocketHandler 他会启动一个服务器并监听某个端口用于给访客访问。当访客访问端口的时候建立起一个访客通道并发送访问请求的数据到ServerSocket(代理服务端);ServerSocketHandler 启动代理服务端根据消息类型的不同处理消息的转发。当第一次和代理客户端相连接注册起主通道用来传输指令和唤起路由通道。ProxySocketHandler 启动代理客户端接收访客数据并解析转发给内网服务。ServiceSocketHandler 启动内网服务端新建一条路由通道发送CONNECT消息给代理服务端注册该通道。处理器对响应Read到的数据进行封装成TYPE_TRANSFER的消息转发给代理服务端转发对应的访客通道。
四个Socket端和对应四个Handler和对应protocol协议你数数加起来才几个类 1234… 是的也就才十一个类再加一个server和client两个模块下的Constant也才13个类就完成了Netty实现的内网穿透是不是非常简单呢
爷的结束语 最近期末周准备投简历有点忙不过来等我结束这段时间我把内网穿透完善一下在下篇文章我就开源出来供大家使用、扩展自己需求。请xdm多多支持感谢铁铁们。 凌晨一点半了晚安各位Zzzzzzzzzzzzzzzzzzzzzzzzzzz