1. 程式人生 > >netty初步認識

netty初步認識

配置 decode name 業務邏輯 try dwr safe election sim

package com.hhr.demo;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse; import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpServerCodec; import io.netty.handler.codec.http.HttpVersion;
import io.netty.util.CharsetUtil; //@SpringBootApplication public class Demo1Application { public static void main(String[] args) throws Exception { // SpringApplication.run(Demo1Application.class, args); /** * 定義好EventLoopGroup,定義好Bootstrap(ServerBootstrap)以及使用的channel類型(一般就是NioSocketChannel, * 服務端是NioServerSocketChannel),剩下是業務相關,使用的ChannelInitializer和具體的handler。 * 主要就是2+N(N為自定義的handler數量)個類. * 為了更好的理解和進一步深入Netty,我們先總體認識一下Netty用到的組件及它們在整個Netty架構中是怎麽協調工作的。Netty應用中必不可少的組件: Bootstrap or ServerBootstrap EventLoop EventLoopGroup ChannelPipeline Channel Future or ChannelFuture ChannelInitializer ChannelHandler Bootstrap,一個Netty應用通常由一個Bootstrap開始,它主要作用是配置整個Netty程序,串聯起各個組件。 Handler,為了支持各種協議和處理數據的方式,便誕生了Handler組件。Handler主要用來處理各種事件,這裏的事件很廣泛,比如可以是連接、數據接收、異常、數據轉換等。 ChannelInboundHandler,一個最常用的Handler。這個Handler的作用就是處理接收到數據時的事件,也就是說,我們的業務邏輯一般就是寫在這個Handler裏面的,ChannelInboundHandler就是用來處理我們的核心業務邏輯。 ChannelInitializer,當一個鏈接建立時,我們需要知道怎麽來接收或者發送數據,當然,我們有各種各樣的Handler實現來處理它,那麽ChannelInitializer便是用來配置這些Handler,它會提供一個ChannelPipeline,並把Handler加入到ChannelPipeline。 ChannelPipeline,一個Netty應用基於ChannelPipeline機制,這種機制需要依賴於EventLoop和EventLoopGroup,因為它們三個都和事件或者事件處理相關。 EventLoops的目的是為Channel處理IO操作,一個EventLoop可以為多個Channel服務。 EventLoopGroup會包含多個EventLoop。 Channel代表了一個Socket鏈接,或者其它和IO操作相關的組件,它和EventLoop一起用來參與IO處理。 Future,在Netty中所有的IO操作都是異步的,因此,你不能立刻得知消息是否被正確處理,但是我們可以過一會等它執行完成或者直接註冊一個監聽,具體的實現就是通過Future和ChannelFutures,他們可以註冊一個監聽,當操作執行成功或失敗時監聽會自動觸發。總之,所有的操作都會返回一個ChannelFuture。 */ EventLoopGroup bossGroup = new NioEventLoopGroup(2); EventLoopGroup workerGroup = new NioEventLoopGroup(4);//第一個EventLoopGroup用來專門負責綁定到端口監聽連接事件,而把第二個EventLoopGroup用來處理每個接收到的連接 /** * 1、 如果不指定線程數,則線程數為:CPU的核數*2 2、根據線程個數是否為2的冪次方,采用不同策略初始化chooser 3、產生nThreads個NioEventLoop對象保存在children數組中。 可以理解NioEventLoop就是一個線程,線程NioEventLoop中裏面有如下幾個屬性: 1、NioEventLoopGroup (在父類SingleThreadEventExecutor中) 2、selector 3、provider 4、thread (在父類SingleThreadEventExecutor中) 更通俗點就是: NioEventLoopGroup就是一個線程池,NioEventLoop就是一個線程。NioEventLoopGroup線程池中有N個NioEventLoop線程。 */ ServerBootstrap serverBootstrap = new ServerBootstrap(); try { /** * 1、group:workerGroup保存在 ServerBootstrap對象的childGroup屬性上。 bossGroup保存在ServerBootstrap對象的group屬性上 2、channelFactory:BootstrapChannelFactory類的對象(clazz屬性為:NioServerSocketChannel.class) 3、handler:SimpleServerHandler 4、childHandler */ serverBootstrap.group(bossGroup, workerGroup) /** * 這行代碼的作用為通過反射產生來一個NioServerSocketChannel類的實例,其中這個NioServerSocketChannel類對象有這樣幾個屬性: * SocketChannel、NioServerSocketChannelConfig 、SelectionKey.OP_ACCEPT事件、NioMessageUnsafe、DefaultChannelPipeline */ .channel(NioServerSocketChannel.class)//當一個連接到達,Netty會註冊一個channel,然後EventLoopGroup會分配一個EventLoop綁定到這個channel,在這個channel的整個生命周期過程中,都會由綁定的這個EventLoop來為它服務,而這個EventLoop就是一個線程 .childHandler(new MyChannelInitializer()); ChannelFuture future = serverBootstrap.bind(8999).sync(); future.channel().closeFuture().sync(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } } class MyChannelInitializer extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel ch) throws Exception { // pipeline上添加來一個ChannelInitializer對象,其中重寫來initChannel方法。該方法通過p.addLast()向serverChannel的流水線處理器中加入了一個 ServerBootstrapAcceptor, // 從名字上就可以看出來,這是一個接入器,專門接受新請求,把新的請求扔給某個事件循環器 ChannelPipeline pipeline = ch.pipeline(); // pipeline.addLast(new HttpRequestDecoder()); // pipeline.addLast(new HttpResponseEncoder()); /** * 由於NioEventLoopGroup中維護著多個NioEventLoop,next方法回調用chooser策略找到下一個NioEventLoop,並執行該對象的register方法進行註冊。 */ pipeline.addLast("httpServerCodec", new HttpServerCodec()); System.out.println("---------------------"); pipeline.addLast(new MyHttpHandler()); } } /** * netty自帶了對用的codec類比較方便。 pipeline.addLast("httpServerCodec", new HttpServerCodec()); 自己實現的handler最簡單的方式用SimpleChannelInboundHandler接收HttpRequest方法即可 class MyHttpHandler extends SimpleChannelInboundHandler<HttpRequest> 這裏簡單說下SimpleChannelInboundHandler這個類,他是簡化處理接受信息並處理的一個類,主要做兩件事。 第一件事是根據泛型決定是否處理這個消息,能夠處理就自己處理,不行就交給下一個(可以參考acceptInboundMessage和channelRead方法)。 第二件事是消息的自動回收(有構造函數支持 默認是true),消息的引用計數會減一(所以在其他地方還要使用記得再retain一下)。 不過只用這個handler並不能拿到content,還需要配合ChunkedWriteHandler和HttpObjectAggregator得到FullHttpRequest對象 * */ class MyHttpHandler extends SimpleChannelInboundHandler<HttpRequest> { @Override protected void channelRead0(ChannelHandlerContext ctx, HttpRequest msg) throws Exception { System.out.println("*********************************************************"); System.out.println(msg.getClass()); System.out.println(msg.uri()); System.out.println(msg.method().name()); System.out.println(ctx.channel().remoteAddress()); System.out.println("headers:"); msg.headers().forEach(System.out::println); ByteBuf buf = Unpooled.copiedBuffer("Hello World", CharsetUtil.UTF_8); FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, buf); response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain"); response.headers().set(HttpHeaderNames.CONTENT_LENGTH, buf.readableBytes()); ctx.writeAndFlush(response); // ctx.channel().close(); } /** * 處理WebSocket請求 # 只需要在上面的基礎上增加一個WebSocketServerProtocolHandler即可,完整如下: pipeline.addLast("httpServerCodec", new HttpServerCodec()); pipeline.addLast(new ChunkedWriteHandler()); pipeline.addLast(new HttpObjectAggregator(8096)); pipeline.addLast(new WebSocketServerProtocolHandler("/ws")); 自己的處理器可以接收並處理WebSocketFrame的子類。 */ }

netty初步認識