1.netty系列之:小白福利!手把手教你做一个简单的代理服务器
2.Netty中的Channel之数据冲刷与线程安全(writeAndFlush)
3.å
³äºNettyä¸çº¿ç¨çå°ç»
4.多通道协议有哪些?
netty系列之:小白福利!手把手教你做一个简单的代理服务器
简介
爱因斯坦说过:所有的伟大,都产生于简单的细节中。Netty为我们提供了如此强大的eventloop、channel通过对这些简单东西的discuz的api源码有效利用,可以得到非常强大的应用程序,比如今天要讲的代理。
代理和反向代理相信只要是程序员应该都听过nginx服务器了,这个超级优秀nginx一个很重要的功能就是做反向代理。那么有小伙伴要问了,有反向代理肯定就有正向代理,那么他们两个有什么区别呢?
先讲一下正向代理,举个例子,最近流量明星备受打击,tkmapper 源码虽然被打压,但是明星就是明星,一般人是见不到的,如果有人需要跟明星对话的话,需要首先经过明星的经纪人,有经纪人将话转达给明星。这个经纪人就是正向代理。我们通过正向代理来访问要访问的对象。
那么什么是反向代理呢?比如现在出现了很多人工智能,假如我们跟智能机器人A对话,然后A把我们之间的对话转给了后面的藏着的人,这个人用他的智慧,回答了我们的对话,交由智能机器人A输出,源码世家最终实现了人工智能。这个过程就叫做反向代理。
netty实现代理的原理那么在netty中怎么实现这个代理服务器呢?
首选我们首先代理服务器是一个服务器,所以我们需要在netty中使用ServerBootstrap创建一个服务器:
EventLoopGroupbossGroup=newNioEventLoopGroup(1);EventLoopGroupworkerGroup=newNioEventLoopGroup();try{ ServerBootstrapb=newServerBootstrap();b.group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).handler(newLoggingHandler(LogLevel.INFO)).childHandler(newSimpleDumpProxyInitializer(REMOTE_HOST,REMOTE_PORT)).childOption(ChannelOption.AUTO_READ,false).bind(LOCAL_PORT).sync().channel().closeFuture().sync();在这个local服务器中,我们传入ProxyInitializer。在这个handler初始化器中,我们传入自定义的handler:
publicvoidinitChannel(SocketChannelch){ ch.pipeline().addLast(newLoggingHandler(LogLevel.INFO),newSimpleDumpProxyInboundHandler(remoteHost,remotePort));}在自定义的handler中,我们使用Bootstrap创建一个client,用来连接远程要代理的服务器,我们将这个client端的创建放在channelActive方法中:
//开启outbound连接Bootstrapb=newBootstrap();b.group(inboundChannel.eventLoop()).channel(ctx.channel().getClass()).handler(newSimpleDumpProxyOutboundHandler(inboundChannel)).option(ChannelOption.AUTO_READ,false);ChannelFuturef=b.connect(remoteHost,remotePort);然后在client建立好连接之后,就可以从inboundChannel中读取数据了:
outboundChannel=f.channel();f.addListener(future->{ if(future.isSuccess()){ //连接建立完毕,读取inbound数据inboundChannel.read();}else{ //关闭inboundchannelinboundChannel.close();}});因为是代理服务,所以需要将inboundChannel读取的数据,转发给outboundChannel,fsk源码所以在channelRead中我们需要这样写:
publicvoidchannelRead(finalChannelHandlerContextctx,Objectmsg){ //将inboundChannel中的消息读取,并写入到outboundChannelif(outboundChannel.isActive()){ outboundChannel.writeAndFlush(msg).addListener((ChannelFutureListener)future->{ if(future.isSuccess()){ //flush成功,读取下一个消息ctx.channel().read();}else{ future.channel().close();}});}}当outboundChannel写成功之后,再继续inboundChannel的读取工作。
同样对于client的outboundChannel来说,也有一个handler,在这个handler中,我们需要将outboundChannel读取到的数据反写会inboundChannel中:
publicvoidchannelRead(finalChannelHandlerContextctx,Objectmsg){ //将outboundChannel中的消息读取,并写入到inboundChannel中inboundChannel.writeAndFlush(msg).addListener((ChannelFutureListener)future->{ if(future.isSuccess()){ ctx.channel().read();}else{ future.channel().close();}});}当inboundChannel写成功之后,再继续outboundChannel的读取工作。
如此一个简单的代理服务器就完成了。
实战如果我们将本地的端口,代理到www..com的端口,会发生什么情况呢?运行我们的aihaoz源码程序,访问, 所以服务器端不认识我们的请求,从而报错。
总结本文的代理服务器之间简单的转发请求,并不能够处理上述的场景,那么该怎么解决上面的问题呢? 敬请期待我的后续文章!
本文的例子可以参考:learn-netty4
最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!
欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!
Netty中的Channel之数据冲刷与线程安全(writeAndFlush)
在Netty框架中,`ChannelHandlerContext`用于处理与`Channel`交互。要了解数据冲刷与线程安全,需先理解`Channel`及其相关组件。
数据冲刷通常在`channelRead`方法中进行。在这个方法中,可利用`ChannelHandlerContext`获取`Channel`实例,从而冲刷数据。
冲刷数据前,需要创建一个`ByteBuf`对象。`ByteBuf`是Netty提供的对`byte[]`和`ByteBuffer NIO`的抽象,其描述为“零个或多个字节的随机和顺序可访问的序列”。使用`Unpooled`工具类创建`ByteBuf`,然后通过`copiedBuffer`方法获取新的缓冲区,内容为指定的UTF-8编码的字符串。
数据冲刷后,会得到一个`ChannelFuture`对象。该对象是异步I/O操作的结果,继承自`Future`接口,用于监听冲刷结果。
要测试线程安全,可以使用`Executor`来模拟多线程执行数据冲刷。`Executor`简化了线程管理,只需传递`Runnable`即可执行任务。测试代码中,使用`retain`方法保留`ByteBuf`对象,理解非保留和保留派生缓冲区的差异。
Netty的`Channel`实现是线程安全的,因此可以安全地在多个线程间共享引用,保证消息顺序发送。
总结,Netty中的`Channel`数据冲刷涉及`ByteBuf`创建、`ChannelFuture`监听及线程安全测试。深入了解这些组件及其交互,能更高效地进行网络应用开发。
å ³äºNettyä¸çº¿ç¨çå°ç»
1. ä¸ä¸ªEventLoopGroupå½ä¸ä¼å å«ä¸ä¸ªæè å¤ä¸ªEventLoop.2. ä¸ä¸ªEventLoopå¨å®çæ´ä¸ªçå½å¨æä¸é½åªä¼ä¸å¯ä¸ä¸ä¸ªThreadè¿è¡ç»å®
3. ææç±EventLoopæå¤ççåç§I/Oäºä»¶é½å°å¨å®æå ³èçé£ä¸ªThreadä¸è¿è¡å¤ç
4. ä¸ä¸ªChannelå¨å®çæ´ä¸ªçå½å¨æä¸åªä¼æ³¨åå¨ä¸ä¸ªEventLoopä¸
5. ä¸ä¸ªEventLoopå¨è¿è¡è¿ç¨å½ä¸,ä¼è¢«åé ç»ä¸ä¸ªæè å¤ä¸ªChannel.
ä¸: å¨Nettyä¸,Channelçå®ç°ä¸å®æ¯çº¿ç¨å®å ¨ç;åºäºæ¤,æ们å¯ä»¥åå¨ä¸ä¸ªChannelçå¼ç¨,并ä¸å¨éè¦åè¿ç¨ç«¯ç¹åéæ°æ®æ¶,éè¿è¿ä¸ªå¼ç¨æ¥è°ç¨Channelç¸åºçæ¹æ³;å³ä½¿å½æ¶æå¾å¤çº¿ç¨é½å¨ä½¿ç¨å®ä¹ä¸ä¼åºç°å¤çº¿ç¨é®é¢;èä¸,æ¶æ¯ä¸å®ä¼æç §é¡ºåºåéåºå».
äº: æ们å¨ä¸å¡å¼åä¸,ä¸è¦å°é¿æ¶é´æ§è¡çèæ¶ä»»å¡æ¾å ¥å°EventLoopçæ§è¡éåä¸,å 为å®å°ä¼ä¸ç´é»å¡è¯¥çº¿ç¨æ对åºçææChannelä¸çå ¶ä»ä»»å¡,å¦ææ们éè¦è¿è¡é»å¡è°ç¨ææ¯èæ¶çæä½,å¯ä»¥ä½¿ç¨ä¸ä¸ªä¸é¨ç线ç¨æ± æ¥å¤ç.
é常ä¼æ两ç§æ¹æ³
1.å¨ChannelHandlerçåè°æ¹æ³ä¸,使ç¨èªå·±å®ä¹ç线ç¨æ± ,è¿æ ·å°±å¯ä»¥å®ç°å¼æ¥è°ç¨
2.åå©äºNettyæä¾çåChannelPipelineæ·»å ChannelHandleræ¶è°ç¨çaddLastæ¹æ³æ¥ä¼ éEventExecutor.
è¿ä¸ªä¹è¯´æäº,é»è®¤æ åµä¸,è°ç¨addLast(handler),ChannelHandlerä¸çåè°æ¹æ³é½æ¯ç±I/O线ç¨æ§è¡ç,å¦æè°ç¨ChannelPipeline addlast(EventExecutorGroup group,ChannelHandler...handler);æ¹æ³,é£ä¹ChannelHandlerä¸çåè°æ¹æ³å°±æ¯ç±åæ°ä¸çgroup线ç¨ç»æ¥æ§è¡ç.
æ¤å¤,JDKææä¾çFutureåªè½éè¿æå·¥æ¹å¼æ£æ¥æ§è¡ç»æ,èè¿ä¸ªæä½æ¯ä¼é»å¡ç;
Nettyé对ChannelFutureè¿è¡äºå¢å¼º,éè¿ChannelFutueListener以åè°çæ¹å¼æ¥è·åæ§è¡ç»æ,å»é¤äºæå·¥æ£æ¥é»å¡çæä½;
ä½åæ¶ChannelFutureListenerçoperationCompleteæ¹æ³æ¯ç±I/O线ç¨æ§è¡ç,å æ¤è¦æ³¨æçæ¯ä¸è¦å¨è¿éæ§è¡èæ¶æä½.
多通道协议有哪些?
多通道协议,在TCP三次握手后,协议双方会“私下”协商一个或多个通道,用于传输信令或数据。例如:FTP、H.、Netty。Netty的主要目的是基于NIO构建具有网络和业务逻辑组件的分离和松耦合的高性能协议服务器。它可以实现多种协议,例如HTTP或自己的特定协议。
Netty有一系列丰富的特性:有一套统一的API来处理异步和同步编程模式;使用非常灵活;简单但却强大的线程机制;业务组件分离方便重用;极小的缩减不必要的Memory Copy。
扩展资料netty核心组件
1、Channel
Channel是Java NIO的基础。表示一个开放的连接,能够执行IO操作,例如读取和写入。简单的说,Channel 就是代表连接,实体之间的连接,程序之间的连接,文件之间的连接,设备之间的连接。同时也是数据入站和出站的载体。
2、Future
Netty 通道中的每个IO操作都是非阻塞的。这意味着调用后立即返回所有操作。标准Java库中有一个Future接口,但是对于Netty而言并不方便-我们只能向Future询问操作的完成情况,或在操作完成之前阻塞当前线程。这就是Netty拥有自己的ChannelFuture接口的原因。可以将回调传递给ChannelFuture,该回调将在操作完成时被调用。