Netty简介及简单使用本文转载请联系源码学徒公众号。一、Netty的优点虽然我在学习NIO的时候已经尽可能的简化了代码,但是我们还是会发现JDKNIO的开发还是异常的复杂。在业务开发中,还需要考虑业务流程,服务的复用,请求并发量,请求过程中的编解码问题,网络传输中的半包粘性问题等等,都会进一步增加难度NIO的发展!Netty针对以上问题提供了统一的解决方案,Netty为Socket编程提供了统一的模板,即使是没有网络编程基础的开发者也可以轻松开发出高并发、低延迟的程序!Netty提供了很多默认的编解码功能,可以很方便的实现一些市面上常见的协议,如FTP、HTTP、SMTP、WebSocket等,可以很容易的解决网络通信过程中的半包和粘包问题。几行代码!强大的定制能力,Netty优秀的代码风格和强大的扩展能力,让我们可以通过ChannelHandler灵活扩展通信框架,通过管道流(PipLine)实现业务功能的相互隔离和复用!成熟稳定,Netty修复了,现在JDK发现了,都是JDKNIOBUG,其中最著名的就是臭名昭著的JDK空练BUG!社区活跃,版本迭代周期短,发现BUG能及时修复。同时,还会增加更多的新功能;,Netty架构设计这是来自官网的架构图,我们可以大致了解Netty的各个模块!事件的可扩展模型,网络通信编程的通用API,数据零拷贝和数据载体的封装和复用!TransportService服务传输层,Netty提供了底层网络通信的能力,将底层网络TCP、UDP等协议进行了网络通信的抽象,让用户不用担心网络通信底层技术的开发,仿佛他们可以更专注于业务!正是因为有了这层封装,NIO/BIO之间的无缝切换成为可能!Protocol支持协议层,Netty几乎实现了市面上大部分主流协议,包括HTTP、SSL、Protobuf、压缩、大文件传输、WebSocket、文本、二进制等主流协议,Netty支持自定义扩展协议。Netty丰富的协议大大降低了用户的开发成本。使用内置协议可以轻松开发类似Tomcat的Http服务器!3.Netty的基本使用和介绍经过上面的介绍,我们对Netty的基本架构有了一个大概的了解,下面我们来看看Netty的基本使用,接下来我会逐行分析。希望本课能帮助大家入门Netty编程,同时也为后面的源码学习做铺垫!1.开发服务器我们使用Netty开发一个简单的服务器代码:服务器接收到客户端的消息,打印出来,然后主动中断连接!启动服务端源码:/***serverprinthandler**@authorhuangfu*@date2021年4月19日12:42:34*/publicclassEchoServerHandlerextendsChannelInboundHandlerAdapter{@OverridepublicvoidchannelRead(ChannelHandlerContextctx,Objectmsg)throwsException{ByteBufbyteBuf=(ByteBuf)msg;try{//转换为字符串Stringmessage=byteBuf.sets.System_FChar);(Standardout.println(message);}finally{ReferenceCountUtil.release(byteBuf);ctx.channel().close();}}}2.服务器源代码介绍EventLoopGroupboss=newNioEventLoopGroup(1);EventLoopGroupworker=newNioEventLoopGroup();定义两个事件循环组,还记得我们第五章优化过的NIO版本吗?现在可以理解为两个选择器组:boss内部只包含一个选择器,用来接收新的连接worker里面默认是CPU*2的selector,用来处理我们的业务逻辑的!boss接收到新的连接后,会把新的connecti产生的SocketChannel交出来交给工作线程组处理!用现在流行的比喻:boss相当于老板,worker相当于worker,老板不处理工作,只负责在外经营业务和谈判合同接到新工作后,把这份工作交给工人,然后再去下一份工作!这两行代码推荐参考上一章NIO优化版学习!ServerBootstrapserverBootstrap=newServerBootstrap();ServerBootstrap是Netty为我们提供的一个快速启动配置类。Netty为什么比NIO更容易开发,是因为Netty为我们提供了网络编程代码的模板。如果你想使用这些模板,你必须告诉模板一些必要的参数,为模板读取,而ServerBootstrap正式扮演了这个角色。我们在初始化的时候设置了各种参数,我们把它们保存在ServerBootstrap中。后续Netty服务启动时,会读取我们在初始化时配置的各种参数,完成自己的初始化!serverBootstrap.group(boss,worker)绑定了我们之前初始化的两个事件循环组,保存在serverBootstrap中,方便后续阅读!.,这是Netty官方对通信通道的扩展:NioServerSocketChannel:服务端通道NioSocketChannel:客户端通道有两个通道,后面我们会详细分析,这里大家先记住,NioServerSocketChannel代表的是服务端通道!NioSocketChannel代表客户端通道,不要混淆!.localAddress(8989)设置一个端口号,服务端暴露的端口号!.childHandler(newChannelInitializer(){@OverrideprotectedvoidinitChannel(SocketChannelsocketChannel)throwsException{socketChannel.pipeline().addLast(newEchoServerHandler());}});这段代码极其重要,后面会提到。主要是服务安排。我想给客户端Socket绑定一个channel,并添加我们的业务处理类xxxxHandler,当一个客户端连接到服务器后,所有后续的业务处理都将由这里注册的各种Handler来处理。这是Netty提供的让开发者专注于业务开发的主要逻辑,后面我会重点讲解这段代码,这里我们只需要记住我们注册完这些Handlers之后,客户端发送过来的数据会在这些Handler中处理!ChannelFuturechannelFuture=serverBootstrap.bind().sync();以上初始化完成,开始服务器启动和端口绑定。根据上面设置的端口号绑定,细心的同学可能会发现我还调用了一个sync方法。Netty是基于异步事件开发的。这里我们进行bind调用后,因为是异步执行的,不知道什么时候完成,所以这里调用了一个阻塞方法(sync),一直阻塞到绑定完成后才继续往下!channelFuture.channel().closeFuture().sync();获取服务端通道对象,并为服务端通道对象添加一个关闭的监听器,并调用阻塞方法(sync)。调用之后,程序会一直阻塞在这里,等待服务端管道关闭,才会继续往下走!一般来说,除非我们主动关机或异常崩溃,否则服务器管道会一直存活,那么修改后的程序就会一直阻塞在这里,形成一个服务!boss.shutdownGracefully();worker.shutdownGracefully();优雅关机,本程序会将通道标记为不可用,等待程序处理完毕,释放Netty创建的所有资源!publicvoidchannelRead(ChannelHandlerContextctx,Objectmsg)throwsException{....}当服务端检测到客户端发送的数据时,会回调逻辑!3.开发客户端/***打印程序客户端**@authorhuangfu*@date2021年4月19日13:58:16*/publicclassEchoClient{publicstaticvoidmain(String[]args){EventLoopGroupworker=newNioEventLoopGroup();try{Bootstrapbootstrap=newBootstrap();bootstrap.remoteAddress("127.0.0.1",8989).group(worker).channel(NioSocketChannel.class)。处理程序(newChannelInitializer(){@OverrideprotectedvoidinitChannel(SocketChannelch)throwsException{ch.pipeline().addLast(newEchoClientHandler());}});ChannelFuturechannelFuture=bootstrap.connect().sync();channelFuture.channel()closeFuture().sync();}catch(Exceptione){e.printStackTrace();}finally{worker.shutdownGracefully();}}}客户端处理Handler/***@authorhuangfu*@date*/publicclassEchoClientHandlerextendsChannelInboundHandlerAdapter{@OverridepublicvoidchannelActive(ChannelHandlerContextctx)throwsException{ByteBufbuffer=ByteBufAllocator.DEFAULT.buffer();buffer.writeBytes("HelloNetty".getBytes(StandardCharsets.UTF_8));ctx.channel().writeAndFlush(bufferclient);}}4.代码介绍客户端代码和服务端代码基本一致,这里就不一一解释了,只说一个不一样的:EventLoopGroupworker=newNioEventLoopGroup();这里客户端只有一个事件循环组,为什么?因为客户端上没有新建连接!Bootstrapbootstrap=newBootstrap();这个和服务器端的ServerBootstrap基本一样,就是设置保存客户端A类的配置!ChannelFuturechannelFuture=bootstrap.connect().sync();连接到服务器并等待连接完成!Handler的重载方法也变了:publicvoidchannelActive(ChannelHandlerContextctx)throwsException{....}这里的意思是,当client被激活并连接到server时,这个逻辑就会被回调!细心的同学在练习的时候可能会发现一些问题。我们发现客户端有两个方法:handler和childHandler。handler()//setservicePipeline.childHandler()handler:绑定在ServerSocketChannel上,负责服务器的逻辑处理!childHandler:绑定在SockerChannel上,当客户端绑定成功后,会生成一个SocketChannel对象,调用handler进行绑定!小结本节课比较简单,主要是对Netty的基本使用有一个比较简单的了解,希望大家课后多多练习,力求简单使用Netty!