netty整理

Netty概述
Netty是一个高性能、异步事件驱动的NIO框架,它提供了对TCP、UDP和文件传输的支持。

  • 高并发 :基于NIO,较BIO效率大大提升。
  • 传输快 :依赖NIO的零拷贝特性。
  • 封装好 : Netty对NIO大部分操作进行了封装,提供易于使用的API,使开发者能能够快速高效的构建一个稳健的高并发应用。

Netty的Reactor线程模型
在这里插入图片描述
主从多线程的Reactor模型
mainReacotor,subReactor,Thread Pool均为线程池。
mainReactor负责处理client连接请求,mainReactor负责处理客户端的连接请求,并将accept的连接注册到subReactor的其中一个线程上。(acceptor仅仅完成登录、握手、安全认证等操作)
subReactor负责处理客户端通道上的数据读写
Thread Pool是具体的业务逻辑线程池,处理具体业务。


Netty具体线程模型
在这里插入图片描述

  1. ServerBootStrap:服务端启动辅助类,负责初始化、注册、绑定等工作。

    public class serverDemo{
    	//线程数默认为CPU核心数*2
        EventLoopGroup bossgroup = new NioEventLoopGroup(1);
        EventLoopGroup workgroup = new NioEventLoopGroup(3);
        try{
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossgroup,workgroup)
             .channel(NioServerSocketChannel.class)
             .option(ChannelOption.SO_BACKLOG,100)
             //设置业务职责链
             //初始化时生效
             .handler(new LoggingHandler(LogLevel.INFO))
             //发生连接时生效
             .childHandler(new HttpServerInitializer());
     
     	//绑定端口
        ChannelFuture f = b.bind(port).sync();
        f.channel().closeFuture().sync();
    }finally {
        bossgroup.shutdownGracefully();
        workgroup.shutdownGracefully();
    }
    

}

public class HttpServerInitializer extends ChannelInitializer<SocketChannel> {
    protected void initChannel(SocketChannel sc) throws Exception {
        ChannelPipeline pipeline = sc.pipeline();
        //处理http消息的编解码
        pipeline.addLast("httpServerCodec", new HttpServerCodec());
        //添加自定义的ChannelHandler
        pipeline.addLast("httpServerHandler", new HttpServerHandler());
    }
}

编写责任链:
继承 ChannelInitializer 并实现其中的 initChannel 方法。通过 initChannel 方法参数 sc 得到 ChannelPipeline 的一个实例。当一个新的连接被接受时, 一个新的 Channel 将被创建,同时它会被自动地分配到它专属的 ChannelPipeline。


  1. Channel:可以把 Channel 看作是传入(入站)或者传出(出站)数据的载体。
    bind() 方法调用时,将会创建一个 ServerChannel
    当连接被接受时,ServerChannel 将会创建一个新的子 Channel
    ServerChannel 和子 Channel 之间是一对多的关系

public B channel(Class<? extends C> channelClass) {
if (channelClass == null) {
throw new NullPointerException(“channelClass”);
}
// 创建 channelFactory
return channelFactory(new ReflectiveChannelFactory(channelClass));
}

public B channelFactory(ChannelFactory<? extends C> channelFactory) {
    if (channelFactory == null) {
        throw new NullPointerException("channelFactory");
    }
    
    if (this.channelFactory != null) {
        throw new IllegalStateException("channelFactory set already");
    }
    this.channelFactory = channelFactory;
    return (B) this;
 }

调用channel()接口设置 AbstractBootstrap 的成员变量 channelFactory

// Channel工厂类
public class ReflectiveChannelFactory<T extends Channel> implements ChannelFactory<T> {

    private final Class<? extends T> clazz;

    public ReflectiveChannelFactory(Class<? extends T> clazz) {
        if (clazz == null) {
            throw new NullPointerException("clazz");
        }
        this.clazz = clazz;
    }
	
    @Override
    public T newChannel() {
        try {
            // 通过反射来进行常见Channel实例
            return clazz.newInstance();
        } catch (Throwable t) {
            throw new ChannelException("Unable to create Channel from class " + clazz, t);
        }
    }

    @Override
    public String toString() {
        return StringUtil.simpleClassName(clazz) + ".class";
    }
}

ReflectiveChannelFactory通过反射获取channel实例。

channel的四种状态:
ChannelUnregistered:Channel已经被创建,但还未注册到EventLoop
ChannelRegistered:Channel已经被注册到了EventLoop
ChannelActive:Channel处于活动状态(已经连接到它的远程节点)。它现在可以接收和发送数据了
ChannelInactive:Channel没有连接到远程节点


  1. NioEventLoop:实际上就是工作线程,可以直接理解为一个线程。
    每个NioEventLoop都绑定了一个Selector,(Netty中,是由Selector监听IO就绪时间,Channel注册到Selector).
    一个Channel绑定到一个NioEventLoop的Selector,一个Selector可以被多个Channel注册。

    主要职责:
    I/O任务和非I/O任务:
    I/O 任务就是处理 Nio 中 Selector 中注册的 4 种事件。
    SelectionKey.OP_READ :负责读
    SelectionKey.OP_WRITE :负责写
    SelectionKey.OP_CONNECT : 负责注册监听连接操作位,用于判断异步连接结果
    SelectionKey.OP_ACCEPT : 负责处理客户端的请求接入

    非IO任务
    系统 Task:通过调用 NioEventLoop 的 excute(Runnable task) 方法实现, Netty 有很多系统 Task,创建它们的主要
    原因:当 I/O 线程和用户线程同时操作网络资源时,为了防止并发操作导致的锁竞争,将用户线程操作封装成 Task 放
    入消息队列中,由 NioEventLoop 线程执行,由同一个线程执行,不需要考虑多线程并发问题。
    定时任务:通过调用 NioEventLoop 的 schedule(Runnable command,long delay,TimeUnit unit) 方法实现。

    public final class NioEventLoop extends SingleThreadEventLoop {

    private Selector selector;
    private Selector unwrappedSelector;
    private SelectedSelectionKeySet selectedKeys;
    
    private final SelectorProvider provider;
    ......
    

    }
    NioEventLoop 中可以看到使用了NIO的Selector

  2. NioEventLoopGroup: NioEventLoop构成的组。

  3. ChannelHandler:充当了所有处理入站和出站数据的应用程序逻辑的容器。ChannelHandler 主要用来处理各种事件,这里的事件很广泛,比如可以是连接、数据接收、异常、数据转换等。

    ChannelHandler两个重要子接口:
    ChannelInboundHandler——处理入站数据以及各种状态变化;
    ChannelOutboundHandler——处理出站数据并且允许拦截所有的操作。

ChannelInboundHandler接口
以下方法将会在数据被接收时或者 与其对应的Channel状态发生改变时被调用
public interface ChannelInboundHandler extends ChannelHandler {

/**
 * 当Channel已经注册到它的EventLoop并且能够处理I/O时被调用
 */
void channelRegistered(ChannelHandlerContext ctx) throws Exception;

/**
 * 当Channel从它的EventLoop注销并且无法处理任何I/O时被调用
 */
void channelUnregistered(ChannelHandlerContext ctx) throws Exception;

/**
 * 当Channel处于活动状态时被调用;Channel已经连接/绑定并且已经就绪
 */
void channelActive(ChannelHandlerContext ctx) throws Exception;

/**
 * 当Channel离开活动状态并且不再连接它的远程节点时被调用
 */
void channelInactive(ChannelHandlerContext ctx) throws Exception;

/**
 * 当从Channel读取数据时被调用
 */
void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception;

/**
 * 当Channel上的一个读操作完成时被调用
 */
void channelReadComplete(ChannelHandlerContext ctx) throws Exception;

/**
 * 当ChannelnboundHandler.fireUserEventTriggered()方法被调用时被调用,因为一个POJO被传经了ChannelPipeline
 */
void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception;

/**
 * 当Channel的可写状态发生改变时被调用。用户可以确保写操作不会完成得太快(以避免发生OutOfMemoryError)或者可以在Channel变为再次可写时恢复写入。可以通过调用Channel的isWritable()方法来检测Channel的可写性。与可写性相关的阈值可以通过Channel.config().setWriteHighWaterMark()和Channel.config().setWriteLowWater-Mark()方法来设置
 */
void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception;

/**
 * 如果抛出一个可抛出的异常对象,则调用。
 */
@Override
@SuppressWarnings("deprecation")
void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;

}

ChannelOutboundHandler接口
出站操作和数据将由ChannelOutboundHandler处理。它的方法将被Channel、ChannelPipeline以及ChannelHandlerContext调用
public interface ChannelOutboundHandler extends ChannelHandler {
/**
* 当请求将Channel绑定到本地地址时被调用
*/
void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception;

/**
 * 当请求将Channel连接到远程节点时被调用
 */
void connect(
        ChannelHandlerContext ctx, SocketAddress remoteAddress,
        SocketAddress localAddress, ChannelPromise promise) throws Exception;

/**
 * 当请求将Channel从远程节点断开时被调用
 */
void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception;

/**
 * 当请求关闭Channel时被调用
 */
void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception;

/**
 * 当请求将Channel从它的EventLoop注销时被调用
 */
void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception;

/**
 * 当请求从Channel读取更多的数据时被调用
 */
void read(ChannelHandlerContext ctx) throws Exception;

/**
 * 当请求通过Channel将数据写到远程节点时被调用
 */
void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception;

/**
 * 当请求通过Channel将入队数据冲刷到远程节点时被调用
 */
void flush(ChannelHandlerContext ctx) throws Exception;

}


  1. ChannelPipeline:ChannelPipeline 为 ChannelHandler 链提供了一个容器并定义了用于沿着链传播入站和出站事件流的 API。保证ChannelHandler之间的处理顺序。

ChannelHandlerContext:

ChannelHandlerContext代表了ChannelHandler与ChannelPipeline之间的关联,当ChannelHandler被添加至ChannelPipeline中时其被创建,ChannelHandlerContext的主要功能是管理相关ChannelHandler与同一ChannelPipeline中的其他ChannelHandler的交互。

一个事件要么被ChannelInboundHander处理,要么被ChannelOutboundHandler处理,随后,它将通过调用ChannelHandlerContext的实现来将事件转发至同一超类型的下一个处理器

一个Channel包含了一个ChannelPipeline,而ChannelPipeline中又维护了一个由ChannelHandlerContext组成的双向链表。这个链表的头是HeadContext,链表的尾是TailContext,并且每个ChannelHandlerContext中又关联着一个ChannelHandler。

参考及转载文章地址:
https://blog.csdn.net/u013857458/article/details/82527722
https://blog.csdn.net/cj2580/article/details/78124780
https://blog.csdn.net/liushu427/article/details/79482080
https://blog.csdn.net/chenssy/article/details/78703551
https://blog.csdn.net/tarenaww/article/details/83620145
https://www.jianshu.com/p/9e5e45a23309
https://blog.csdn.net/qq_37598011/article/details/83957860

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值