• 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. 欢迎广大读者围观

  • 相关阅读:
    (转)Android dumpsys命令详细使用
    转Android Canvas drawArc方法介绍
    13如何触发选中指定Tree节点的选中状态及事件/操作tree数据后刷新数据后保留原来的收缩展开状态
    24动态设置浏览器tab标题(afterEach后置路由守卫的运用)/路由传参8种方式
    20封装一个方法,传入目标对象和key(数组和索引),通过传入的索引判断数组是新增还是修改
    12elcheckbox复选框和文字单独的事件
    15手动全屏loading
    05对数组中的对象去重(两个对象中的key和value完全一样)利用Set数据结构的天然特性去重
    211 js数据结构——堆栈
    1为什么要使用encodeURIComponent
  • 原文地址:https://www.cnblogs.com/zou90512/p/3908022.html
Copyright © 2020-2023  润新知