<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                在學習netty源碼之前,應該對netty的基本用法有所了解,由于netty大多數時候用于開發服務器端程序,因此下面以一個時間服務器為例,演示Netty的基本使用,并對主要概念進行介紹。 ## 2.1 服務器啟動程序 時間服務器很簡單,每次收到`QUERY TIME ORDER`請求后返回當前時間。 1. main方法中通過ServerBootstrap啟動netty服務器 ``` //創建兩個線程組,專門用于網絡事件的處理,Reactor線程組 //一個用來接收客戶端的連接, //一個用來進行SocketChannel的網絡讀寫 EventLoopGroup bossGroup=new NioEventLoopGroup(); EventLoopGroup workGroup=new NioEventLoopGroup(); try{ //輔助啟動類 ServerBootstrap b=new ServerBootstrap(); b.group(bossGroup,workGroup) // 注冊兩個線程組 .channel(NioServerSocketChannel.class)//創建的channel為NioServerSocketChannel【nio-ServerSocketChannel】 .option(ChannelOption.SO_BACKLOG, 1024) // 設置TCP屬性 .childOption(ChannelOption.SO_KEEPALIVE, true) //配置accepted的channel屬性 .childHandler(new ChildChannelHandler());//處理IO事件的處理類,處理網絡事件 ChannelFuture f=b.bind(port).sync();//綁定端口后同步等待 f.channel().closeFuture().sync();//阻塞 }catch(Exception e){ e.printStackTrace(); }finally{ bossGroup.shutdownGracefully(); workGroup.shutdownGracefully(); } ``` 2. 定義ChannelInitializer,會在ServerChannel注冊到事件循環后觸發initChannel事件。 ``` // ChannelHandler初始化處理器 class ChildChannelHandler extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new TimeServerHandler()); } } ``` 3. TimeServerHandler 里面負責處理業務邏輯,發送當前時間 ``` public class TimeServerHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ByteBuf buf=(ByteBuf) msg;//將msg轉換成Netty的ByteBuf對象 byte[] req=new byte[buf.readableBytes()]; buf.readBytes(req); String body=new String(req,"GBK"); System.out.println("The time server receive order : "+body); String currentTime="QUERY TIME ORDER".equalsIgnoreCase(body)?new Date(System.currentTimeMillis()).toString():"BAD ORDER"; ByteBuf resp=Unpooled.copiedBuffer(currentTime.getBytes()); ctx.write(resp);//只是寫入緩沖區 } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.flush();//通過網絡發送 } } ``` ## 2.2 過程解析 1. 創建輔助啟動類ServerBootstrap,并設置相關配置: * group() 設置處理Accept事件和讀寫操作的事件循環組 * channel() 設置通道類型為NioServerSocketChannel,這是netty自己定義的Channel,指的是服務器通道,內部包含java中的ServerSocketChannel,相應的還有客戶端通道NioSocketChannel。 * option()/childOption() 設置服務器通道的選項和建立連接后的客戶端通道的選項 * childHandler() 設置子處理器,內部需要將戶自定義的處理器加入到netty中,這涉及到Channel,ChannelHandler和Pipeline,后續會有講解 2.調用bind()方法綁定端口,sync()會阻塞等待處理請求。這是因為bind()方法是一個異步過程,會立即返回一個ChannelFuture對象,調用sync()會等待執行完成。 3.獲得Channel的closeFuture阻塞等待關閉,服務器Channel關閉時closeFuture會完成。 > Future的使用參見【第四章 Future和Promise】 ## 2.3 相關概念 在學習Netty的源碼之前,需要對Netty的主要概念進行了解,主要是初步明白每個類負責的任務是什么,能夠完成哪些工作。當然,每個概念的具體實現會在后續章節中進行介紹。 **Channel** 這里的Channel與Java的Channel不是同一個,是netty自己定義的通道;Netty的Channel是對網絡連接處理的抽象,負責與網絡進行通訊,支持NIO和OIO兩種方式;內部與網絡socket連接,通過channel能夠進行I/O操作,如讀、寫、連接和綁定。 通過Channel可以執行具體的I/O操作,如read, write, connect, 和bind。在Netty中,所有I/O操作都是異步的;Netty的服務器端處理客戶端連接的Channel創建時可以設置父Channel。例如:ServerSocketChannel接收到請求創建SocketChannel,SocketChannel的父為ServerSocketChannel。 **ChannelHandler與ChannelPipeline** ChannelHandler是通道處理器,用來處理I/O事件或攔截I/O操作,ChannelPipeline字如其名,是一個雙向流水線,內部維護了多個ChannelHandler,服務器端收到I/O事件后,每次順著ChannelPipeline依次調用ChannelHandler的相關方法。 ChannelHandler是個接口,通常我們在Netty中需要使用下面的子類: * ChannelInboundHandler 用來處理輸入的I/O事件 * ChannelOutboundHandler 用來處理輸出的I/O事件 另外,下面的adapter類提供了 * ChannelInboundHandlerAdapter 用來處理輸入的I/O事件 * ChannelOutboundHandlerAdapter 用來處理輸出的I/O事件 * ChannelDuplexHandler 可以用來處理輸入和輸出的I/O事件 Netty的ChannelPipeline和ChannelHandler機制類似于Servlet和Filter過濾器/攔截器,每次收到請求會依次調用配置好的攔截器鏈。Netty服務器收到消息后,將消息在ChannelPipeline中流動和傳遞,途經的ChannelHandler會對消息進行處理,ChannelHandler分為兩種inbound和outbound,服務器read過程中只會調用inbound的方法,write時只尋找鏈中的outbound的Handler。 ChannelPipeline內部維護了一個雙向鏈表,Head和Tail分別代表表頭和表尾,Head作為總入口和總出口,負責底層的網絡讀寫操作;用戶自己定義的ChannelHandler會被添加到鏈表中,這樣就可以對I/O事件進行攔截和處理;這樣的好處在于用戶可以方便的通過新增和刪除鏈表中的ChannelHandler來實現不同的業務邏輯,不需要對已有的ChannelHandler進行修改。 ![NettyPipeline](http://web.uxiaowo.com/netty/Future/Pipeline.png) 如圖所示,在服務器初始化后,ServerSocketChannel的會創建一個Pipeline,內部維護了ChannelHanlder的雙向鏈表,讀取數據時,會依次調用ChannelInboundHandler子類的channelRead()方法,例如:讀取到客戶端數據后,依次調用解碼-業務邏輯-直到Tail。 而寫入數據時,會從用戶自定義的ChannelHandler出發查找ChannelOutboundHandler的子類,調用channelWrite(),最終由Head的write()向socket寫入數據。例如:寫入數據會通過業務邏輯的組裝--編碼--寫入socket(Head的write)。 **EventLoop與EventLoopGroup** EventLoop是事件循環,EventLoopGroup是運行在線程池中的事件循環組,Netty使用了Reactor模型,服務器的連接和讀寫放在線程池之上的事件循環中執行,這是Netty獲得高性能的原因之一。事件循環內部會打開selector,并將Channel注冊到事件循環中,事件循環不斷的進行select()查找準備就緒的描述符;此外,某些系統任務也會被提交到事件循環組中運行。 **ServerBootstrap** ServerBootstrap是輔助啟動類,用于服務端的啟動,內部維護了很多用于啟動和建立連接的屬性。包括: * EventLoopGroup group 線程池組 * channel是通道 * channelFactory 通道工廠,用于創建channel * localAddress 本地地址 * options 通道的選項,主要是TCP連接的屬性 * attrs 用來設置channel的屬性, * handler 通道處理器 ## 2.4 啟動過程 了解了上面的概念后,我們再來根據程序說明一下服務器的啟動過程,主要分為四個階段: * 配置config:設置啟動器/服務器通道/客戶端通道等相關配置; * 初始化init:主要功能是打開java的serversocketchannel,內部會初始化Netty的Channel及其ChannelPipeline; * 注冊register:將初始化后的Netty-Channel注冊到事件循環的selector上面。具體過程:將打開netty的Channel注冊到線程池組的selector上;觸發Pipeline上面ChannelHandler的channelRegistered,至此注冊完畢; * 綁定bind:將java的ServerSocketChannel綁定到本地的端口上面,結束后使用fireChannelActive通知Pipeline里的ChannelHandle,執行其channelActive方法; 由于注冊階段是異步的,綁定階段會與之同時進行,因此注冊階段完畢后會判斷綁定階段是否結束從而觸發channelActive。在啟動完畢后,會建立下圖中的連接結構: ![NettyPipeline](http://web.uxiaowo.com/netty/Future/Channel.png) Netty的Channel一端與java的Channel相連接,可以進行網絡I/O操作;另一端與Pipeline連接,用來執行業務邏輯。一旦事件循環組中的EventLoop在循環中select()到準備就緒的I/O描述符后,就會交給NettyChannel處理,NettyChannel交給Pipeline的鏈表進行業務邏輯處理。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看