1、服务端时序图:
2、编码流程:
- 创建ServerBootstrap实例
- 设置EventLoopGroup
- 设置创建的Channel类型
- option配置属性
- 设置Handler,处理请求
- 设置ChildHandler,处理对应channel的请求
- 通过bind创建Chnnel并绑定,启动服务
serverBootstrap = new ServerBootstrap();
eventLoopGroup = new NioEventLoopGroup();
serverBootstrap.group(eventLoopGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_KEEPALIVE, true)
.handler(new LoggingHandler(LogLevel.INFO));
设置Handler,处理请求
设置ChildHandler,处理对应channel的请求
通过bind创建Chnnel并绑定,启动服务
serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel sc) throws Exception {
sc.pipeline()
.addLast(new ProtocolDecoder(chargeDevice))
.addLast(new ProtocolEncoder())
.addLast(new IdleStateHandler(readerIdleTime, writerIdleTime, allIdleTime, TimeUnit.SECONDS))
.addLast(new MyInboundHandler(chargeDevice));
}
});
this.channelFuture = serverBootstrap.bind(port).sync();
3、服务端重要组件
(1)ServerBootstrap
ServerBootstrap是Netty服务端的启动辅助类,提供一系列的方法用于设置服务端的参数和配置,简化开发。(衍生一点:ServerBootstrap的构造方法是无参的,因为参数太多所以采用了Builder模式)
继承自AbstractBootstrap,核心属性有childGroup和childHandler。
- childGroup:负责调度和执行客户端的接入、网络读写事件的处理、用户自定义任务和定时任务的执行
- childHandler:自定义的业务Handler
AbstractBootstrap核心属性有group和handler。
- group:处理客户端的链接请求,并转交给childGroup(读取的数据是穿件的NioSocketChannel)
(2)Reactor线程池
Netty的Reactor线程池是EventLoopGroup,实际上是一个EventLoop的数组。
EventLoop的职责是处理所有注册到本线程多路复用器Selector上的Channel,Selector的轮训操作有EventLoop线程run方法驱动。
另外用户自定义的Task和定时任务Task也由统一的EventLoop负责处理。
(3)Channel
作为Nio服务,需要创建ServerSocketChannel,Netty对原生NIO类库做了封装,对应实现类为NioServerSocketChannel。
用户只需要制定Channel的实现类型,内部通过反射机制来创建对应的实例。
因为只在监听端口时创建,所以反射的性能影响并不大。
(4)ChannelPipeline
ChannelPipeline是网络事件处理的职责链,负责管理和执行ChannelHandler。网络事件以事件流的形式在ChannelPipeline中流转。
(5)ChannelHandler
ChannelHandler是提供给用户定制和扩展的关键接口,包括编解码,业务处理等都是通过ChannelHandler进行的。
(6)Selector
Selector轮训操作由NioEventLoop调度和执行,选择准备就绪的Channel集合。
(7)NioServerSocketChannel
绑定Server端地址的Server,读取客户端的链接请求(只有一个,在bind时创建)。
(8)NioSocketChannel
和客户端之间的链接。
4、实例
public class NettyServer {
public void bind(int port){
// 创建EventLoopGroup
EventLoopGroup bossGroup = new NioEventLoopGroup(); //创建BOSS线程组 用于服务端接受客户端的连接
EventLoopGroup workerGroup = new NioEventLoopGroup(); //创建WORK线程组 用于进行SocketChannel的网络读写
try {
// 创建ServerBootStrap实例
// ServerBootstrap 用于启动NIO服务端的辅助启动类,目的是降低服务端的开发复杂度
ServerBootstrap b = new ServerBootstrap();
// 绑定Reactor线程池
b.group(bossGroup, workerGroup)
// 设置并绑定服务端Channel
// 指定所使用的NIO传输的Channel
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
.handler(new LoggingServerHandler())
.childHandler(new ChannelInitializer(){
@Override
protected void initChannel(Channel ch) throws Exception {
//do something
}
});
// 绑定端口,同步等待成功
ChannelFuture future = b.bind(port).sync();
// 等待服务端监听端口关闭
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 优雅地关闭
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
private class LoggingServerHandler extends ChannelInboundHandlerAdapter{
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("loggin-channelActive");
}
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
System.out.println("loggin-channelRegistered");
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
System.out.println("loggin-handlerAdded");
}
}
public static void main(String[] args){
new NettyServer().bind(8899);
}
}