Netty介绍 与第一个Netty实例
官網:https://netty.io/
以下內容大部分來自Netty官網內容
一、現有問題
現在我們使用通用應用程序或庫來彼此通信。例如,我們經常使用HTTP客戶端庫從web服務器檢索信息,并通過web服務調用遠程過程調用。然而,一個通用協議或它的實現有時并不能很好地擴展。這就像我們沒有使用通用的HTTP服務器來交換巨大的文件、電子郵件消息和接近實時的消息(如財務信息和多人游戲數據)。需要的是一個高度優化的協議實現,專門用于特定的目的。例如,您可能想實現一個針對基于ajax的聊天應用程序、媒體流或大型文件傳輸進行優化的HTTP服務器。您甚至可能想設計和實現一個全新的協議,它可以根據您的需要進行精確定制。另一種不可避免的情況是,您必須處理遺留的專有協議,以確保與舊系統的互操作性。在這種情況下,重要的是在不犧牲應用程序的穩定性和性能的情況下,我們可以多快地實現該協議。
二、解決方案
Netty項目致力于提供一個異步事件驅動的網絡應用框架和工具,用于快速開發可維護的高性能和高可伸縮性協議服務器和客戶端。
換句話說,Netty是一個NIO客戶端服務器框架,它支持快速而簡單地開發網絡應用程序,如協議服務器和客戶端。它極大地簡化和簡化了網絡編程,如TCP和UDP套接字服務器開發。
“快速和簡單”并不意味著結果應用程序將受到可維護性或性能問題的影響。Netty是經過精心設計的,從許多協議(如FTP、SMTP、HTTP和各種基于二進制和文本的遺留協議)的實現中吸取了經驗。因此,Netty成功地找到了一種方法,可以在不妥協的情況下實現開發的易用性、性能、穩定性和靈活性。
有些用戶可能已經發現了其他聲稱具有相同優勢的網絡應用程序框架,您可能想知道是什么使Netty與它們如此不同。答案是它所建立的哲學。Netty從一開始就為您提供API和實現方面最舒適的體驗。這不是一些有形的東西,但你會意識到,這種哲學將使你的生活更容易,當你閱讀本指南和玩Netty。
三、編寫一個丟棄服務器
世界上最簡單的協議不是“你好,世界!”但丟棄。它是一種丟棄任何接收到的數據而不進行任何響應的協議。
要實現丟棄協議,您需要做的唯一一件事就是忽略所有接收到的數據。讓我們直接從處理程序實現開始,它處理Netty生成的I/O事件。
package io.netty.example.discard;import io.netty.buffer.ByteBuf;import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter;/*** Handles a server-side channel.*/ public class DiscardServerHandler extends ChannelInboundHandlerAdapter { // (1)@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) { // (2)// Discard the received data silently.((ByteBuf) msg).release(); // (3)}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (4)// Close the connection when an exception is raised.cause.printStackTrace();ctx.close();} }實現丟棄服務服務器:
package io.netty.example.discard;import io.netty.bootstrap.ServerBootstrap;import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel;/*** Discards any incoming data.*/ public class DiscardServer {private int port;public DiscardServer(int port) {this.port = port;}public void run() throws Exception {EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)EventLoopGroup workerGroup = new NioEventLoopGroup();try {ServerBootstrap b = new ServerBootstrap(); // (2)b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) // (3).childHandler(new ChannelInitializer<SocketChannel>() { // (4)@Overridepublic void initChannel(SocketChannel ch) throws Exception {ch.pipeline().addLast(new DiscardServerHandler());}}).option(ChannelOption.SO_BACKLOG, 128) // (5).childOption(ChannelOption.SO_KEEPALIVE, true); // (6)// Bind and start to accept incoming connections.ChannelFuture f = b.bind(port).sync(); // (7)// Wait until the server socket is closed.// In this example, this does not happen, but you can do that to gracefully// shut down your server.f.channel().closeFuture().sync();} finally {workerGroup.shutdownGracefully();bossGroup.shutdownGracefully();}}public static void main(String[] args) throws Exception {int port = 8080;if (args.length > 0) {port = Integer.parseInt(args[0]);}new DiscardServer(port).run();} }上述代碼中數字分別代表以下內容:
1.NioEventLoopGroup是一個處理I/O操作的多線程事件循環。Netty為不同類型的傳輸提供了各種EventLoopGroup實現。在本例中,我們將實現一個服務器端應用程序,因此將使用兩個NioEventLoopGroup。第一個,通常稱為“boss”,接受一個傳入連接。第二個,通常稱為“worker”,在老板接受連接并向worker注冊已接受的連接后,處理已接受連接的流量。使用多少線程以及如何將它們映射到創建的通道取決于EventLoopGroup實現,甚至可以通過構造函數進行配置。
2.ServerBootstrap是一個設置服務器的助手類。您可以直接使用通道設置服務器。但是,請注意,這是一個乏味的過程,而且在大多數情況下不需要這樣做。
3.這里,我們指定使用NioServerSocketChannel類,該類用于實例化一個新通道以接受傳入連接。
4.這里指定的處理程序將始終由新接受的通道進行評估。ChannelInitializer是一個特殊的處理程序,用于幫助用戶配置新通道。您很可能希望通過添加一些處理程序(如DiscardServerHandler)來配置新通道的ChannelPipeline,以實現網絡應用程序。隨著應用程序變得越來越復雜,您可能會向管道中添加更多的處理程序,并最終將這個匿名類提取到一個頂級類中。
5.您還可以設置特定于通道實現的參數。我們正在編寫一個TCP/IP服務器,因此允許設置套接字選項,如tcpNoDelay和keepAlive。請參考ChannelOption的apidocs和特定的ChannelConfig實現,以獲得有關受支持的ChannelOptions的概述。
6.您注意到option()和childOption()了嗎?option()用于接受傳入連接的NioServerSocketChannel。childOption()用于父服務器通道(在本例中為NioServerSocketChannel)接受的通道。
7.我們現在準備走了。剩下的工作就是綁定到端口并啟動服務器。在這里,我們綁定到機器中所有nic(網絡接口卡)的端口8080。現在可以任意多次調用bind()方法(使用不同的綁定地址)。
查看接收到的數據
@Override public void channelRead(ChannelHandlerContext ctx, Object msg) {ByteBuf in = (ByteBuf) msg;try {while (in.isReadable()) { // (1)System.out.print((char) in.readByte());System.out.flush();}} finally {ReferenceCountUtil.release(msg); // (2)} }1、他的低效循環實際上可以簡化為:System.out.println(in.toString(io.netty.uti.charsetutil.us_ascii))
2、也可以在這里直接使用in.release()。
編寫回顯服務器
到目前為止,我們一直在使用數據而沒有響應。然而,服務器通常應該響應請求。讓我們學習如何通過實現ECHO協議向客戶端編寫響應消息,接收到的任何數據都會被發回。與我們在前幾節中實現的丟棄服務器的惟一區別是,它將發送回接收到的數據,而不是將接收到的數據打印到控制臺。因此,再次修改channelRead()方法就足夠了:
@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) {ctx.write(msg); //Read完直接寫給客戶端 (1)ctx.flush(); // (2)可直接使用ctx.writeAndFlush(msg)}1、ChannelHandlerContext對象提供各種操作,使您能夠觸發各種I/O事件和操作。在這里,我們調用write(Object)來逐字寫入接收到的消息。請注意,我們沒有像在丟棄示例中那樣釋放接收到的消息。這是因為Netty在將其寫入網絡時為您釋放了它。
2、write(Object)不會將消息寫入網絡。它在內部進行緩沖,然后通過ctx.flush()將其刷新到連接上。或者,為了簡潔,您可以調用ctx.writeAndFlush(msg)。
待續。。
?
?
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的Netty介绍 与第一个Netty实例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 分布式:阿里云HSF转dubbo+zoo
- 下一篇: 虚拟机(VMware Workstati