Netty4.x中文教程系列(六) 從頭開始Bootstrap


Netty4.x中文教程系列(六) 從頭開始Bootstrap

    其實自從中文教程系列(五)一直不知道自己到底想些什么。加上忙着工作上出現了一些問題。本來想就這么放棄維護了。沒想到有朋友和我說百度搜索推薦了我的文章。瞬間有點小激動啊。決定自己要把這個教程系列完善下去。這里誠摯的想支持我的盆友們道歉。真的是讓你們失望了。我居然有想放棄的這種喪心病狂的念頭。以后絕對不會了。

    

    其實伴隨着對Netty的逐步深入學習。感覺自己對netty的了解仍然有所欠缺。加上筆者語文課是美術老師教的。所以。。說多了都是淚啊。~~o(>_<)o ~~

 

 

下面開始正文:

縱覽Netty框架的包結構,不難看出。其實Netty是有五大模塊組成。

  1. Bootstrap負責啟動引導
  2. Buffer是Netty自己封裝的緩存器
  3. Channel負責管理和建立連接
  4. Handler是責任鏈路模式中的處理者
  5. Util是Netty提供和使用到的一些工具

如何啟動Netty服務器

    Netty的啟動服務器相關的類全部都在bootstrap包里面。所以本章我們從頭開始,從bootstrap包里面的內容開始。從創建一個Netty服務器開始為大家逐步講解Netty的應用。

相比於第五章的ChannelHandler里面的編解碼器bootstrap里面可以說是內容少的可憐。來看一下他的包內容:

簡簡單單的三個類,一個接口。

Bootstrap是客戶端的啟動程序類。

ServerBootstrap是服務端的啟動程序類

Bootstrap和ServerBootstrap繼承AbstractBootstrap。

ChannelFactory則是AbstractBootstrap中用於創建Channel的接口

以下代碼以服務端的啟動程序啟動為例:

步驟一:實例化ServerBootstrap

首先我們需要實例化一個ServerBootstrap服務端啟動引導程序。如下圖:

步驟二:設置它的線程組

    創建兩個NioEventLoopGroup,一個是父線程(Boss線程),一個是子線程(work線程)。

設置bootstrap的線程組

設置線程組主要的目的是為了處理Channel中的事件和IO操作。

 

下圖為ServerBootstrap的group方法的源碼:

父線程組被傳遞到父類中。詳細的解釋在最后面。涉及的東西太多。在后面在進行解釋。

步驟三:設置Channel類型

    設置Channel類型:

 

下圖ServerBootstrap中channel()方法的源碼:

 

我們可以看到創建並設置了一個Channel工廠。

下圖是BootstrapChannelFactory的源碼。它是一個終態的靜態的類。實現ChannelFactory。作用是根據初始設置的Channel類型,創建並返回一個新的Channel。

步驟四:設置責任鏈路

    責任鏈模式是Netty的核心部分。每個處理者只負責自己有關的東西。然后將處理結果根據責任鏈傳遞下去。

    我們要在初始的設置一個責任鏈路。當一個Channel被創建之后初始化的時候將被設置。下圖是ServerBootstrap在init()方法的源碼:

創建一個Channel,在初始化的設置管道里面的處理者。

 

步驟五:綁定並監聽端口

    綁定並設置監聽端口。

    經過以上的5個步驟,我們的服務器就足以啟動了。很多的設置都是Netty默認的。我們想設置自己的參數怎么辦呢?Netty提供了這個方法。

 

步驟六:其他設置

1. 設置Channel選項配置:

在Netty 以前的版本中都是以字符串來配置的。4.x版本發布之后統一修改為使用ChannelOption類來實現配置。

例如:

Socket連接是否保存連接:

    還有很多其他的參數。如下圖所示:

這里不詳細講了。參考:io.netty.channel.ChannelOption

 

2. 設置子Channel的屬性:

    設置子Channel的屬性。當值為null是,屬性將被刪除。

 

 

解釋EventLoopGroup

這里解釋一下我們上面創建的兩個完全一樣的線程組的作用。

Netty的架構使用了非常復雜的主從式Reactor線程模型。簡單的說就是。父線程組(代碼中的parentBosser)擔任(acceptor)的角色。負責接收客戶端的連接請求,處理完成請求,創建一個Channel並注冊到子線程組(代碼中的childWorker)中的某個線程上面,然后這個線程將負責Channel的讀寫,編解碼等操作。

 

源代碼查看:

在步驟四中我們設置了責任鏈路。這里是Channel初始化和注冊。在這里的init就是Channel的初始化。初始化完成之后。Group()則是獲取在步驟一種的設置父線程組,並將這個新的Channel注冊進來。

下圖是AbstractBootstrap的initAndRegister方法

 

方法Init()實現在ServerBootstrap中。代碼如下:

看到下面的代碼是不是有種和熟悉的感覺?沒錯。就是在步驟四中設置責任鏈路的那段代碼。這里將注冊新創建的Channel到子線程組

 

Ps: 完。。。O(∩_∩)O哈哈~。。。寫的好辛苦的說。。。附上我的測試示例代碼。好累。。寫這么多字。希望能幫助到大家

 

 1 import io.netty.bootstrap.ServerBootstrap;
 2 import io.netty.channel.*;
 3 import io.netty.channel.nio.NioEventLoopGroup;
 4 import io.netty.channel.socket.nio.NioServerSocketChannel;
 5 import io.netty.channel.socket.nio.NioSocketChannel;
 6 import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
 7 import io.netty.handler.codec.LengthFieldPrepender;
 8 
 9 /**
10  * 測試。。O(∩_∩)O哈哈~
11  * Created by TinyZ on 2014/8/12.
12  */
13 public class MainTest {
14 
15     public static void main(String[] args) throws Exception {
16 
17         NioEventLoopGroup parentBosser = new NioEventLoopGroup();
18         NioEventLoopGroup childWorker = new NioEventLoopGroup();
19 
20         ServerBootstrap bootstrap = new ServerBootstrap();
21         bootstrap.group(parentBosser, childWorker);
22         bootstrap.channel(NioServerSocketChannel.class);
23         bootstrap.childHandler(new ChannelInitializer<NioSocketChannel>() {
24             @Override
25             protected void initChannel(NioSocketChannel ch) throws Exception {
26                 ChannelPipeline cp = ch.pipeline();
27                 // 基於長度的解碼器
28                 cp.addLast("framer", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2, 0, 2));
29                 cp.addLast("prepender", new LengthFieldPrepender(4));
30                 //
31                 cp.addLast("handler", new SimpleChannelInboundHandler<Object>() {
32 
33                     @Override
34                     protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
35 
36                         System.out.println();
37                         ctx.channel().writeAndFlush(msg);
38 
39                     }
40                 });
41             }
42         });
43         bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
44         //bootstrap.childAttr()
45         try {
46             // 綁定並監聽端口
47             ChannelFuture future = bootstrap.bind(9002).sync();
48             // 等待關閉事件
49             future.channel().closeFuture().sync();
50         } finally {
51             // 釋放資源
52             parentBosser.shutdownGracefully();
53             childWorker.shutdownGracefully();
54         }
55     }
56 }
View Code

 

 

作者:TinyZ
出處:http://www.cnblogs.com/zou90512/
關於作者:努力學習,天天向上。不斷探索學習,提升自身價值。記錄經驗分享。
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接
如有問題,可以通過 zou90512@126.com 聯系我,非常感謝。
筆者網店: http://aoleitaisen.taobao.com. 歡迎廣大讀者圍觀

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM