下面开始正文:
纵览Netty框架的包结构,不难看出。其实Netty是有五大模块组成。
-
Bootstrap负责启动引导
-
Buffer是Netty自己封装的缓存器
-
Channel负责管理和建立连接
-
Handler是责任链路模式中的处理者
-
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哈哈~。。。写的好辛苦的说。。。附上我的测试示例代码。好累。。写这么多字。希望能帮助到大家
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
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 }