netty一些概念:同步/异步、阻塞/非阻塞 、NioEventLoopGroup、ServerBootstrap

同步/异步、阻塞/非阻塞

  • 同步异步 : 调用者是否等待结果返回

    • 同步:等待结果响应
    • 异步:不等待结果返回,继续往下走
  • 阻塞非阻塞线程是否阻塞

IO的方式:

  • 同步阻塞的BIO(Blocking I/O)、

BIO (Blocking I/O):同步阻塞I/O模式,数据的读取写入必须阻塞在一个线程内等待其完成。
这里假设一个烧开水的场景,有一排水壶在烧开水,BIO的工作模式就是, 叫一个线程停留在一个水壶那,直到这个水壶烧开,才去处理下一个水壶。但是实际上线程在等待水壶烧开的时间段什么都没有做。

  • 同步非阻塞的NIO(non-blocking I/O 、 new io) :

NIO (New I/O):同时支持阻塞与非阻塞模式,但这里我们以其同步非阻塞I/O模式来说明,那么什么叫做同步非阻塞?
如果还拿烧开水来说,NIO的做法是叫一个线程不断的轮询每个水壶的状态,看看是否有水壶的状态发生了改变,从而进行下一步的操作。

  • 异步非阻塞的AIO(Asynchronous I/O)。

AIO ( Asynchronous I/O):异步非阻塞I/O模型。异步非阻塞与同步非阻塞的区别在哪里?异步非阻塞无需一个线程去轮询所有IO操作的状态改变,在相应的状态改变后,系统会通知对应的线程来处理。
对应到烧开水中就是,为每个水壶上面装了一个开关,水烧开之后,水壶会自动通知我水烧开了。

Bootstrap、ServerBootstrap

在这里插入图片描述

NioEventLoopGroup

在这里插入图片描述

参考:

Netty 教程

Netty是一个异步事件驱动NIO网络通信框架,Netty的所有IO操作都是异步非阻塞的。

Netty 实际上是使用 Threads(多线程)处理 I/O 事件,熟悉多线程编程的读者可能会需要关注同步代码。但是这么做不好,因为同步会影响程序的性能,Netty 的设计保证程序处理事件不会有同步。

在这里插入图片描述

Channel :表示一个连接

  • Channel,一个客户端与服务器通信的通道,表示一个连接,可以理解为每一个请求,就是一个Channel。

Channel和IO中的Stream(流)是差不多一个等级的。
只不过Stream是单向的,譬如:InputStream, OutputStream.而Channel是双向的,既可以用来进行读操作,又可以用来进行写操作。

NIO中的Channel的主要实现有 :
FileChannel
DatagramChannel
SocketChannel
ServerSocketChannel

底层网络传输 API 必须提供给应用 I/O操作的接口,如读,写,连接,绑定等等。对于我们来说,这是结构几乎总是会成为一个“socket”。 Netty 中的接口 Channel 定义了与 socket 丰富交互的操作集:bind, close, config, connect, isActive, isOpen, isWritable, read, write 等等。 Netty 提供大量的 Channel 实现来专门使用。这些包括 AbstractChannel,AbstractNioByteChannel,AbstractNioChannel,EmbeddedChannel, LocalServerChannel,NioSocketChannel 等等。

ChannelHandler : 处理逻辑业务

  • ChannelHandler,业务逻辑处理器,核心处理业务就在这里,用于处理业务请求。

分为ChannelInboundHandler和ChannelOutboundHandler

  • ChannelInboundHandler,输入数据处理器
  • ChannelOutboundHandler,输出业务处理器

通常情况下,业务逻辑都是存在于ChannelHandler之中.

ChannelHandler 支持很多协议,并且提供用于数据处理的容器。我们已经知道 ChannelHandler 由特定事件触发。 ChannelHandler 可专用于几乎所有的动作,包括将一个对象转为字节(或相反),执行过程中抛出的异常处理。

常用的一个接口是 ChannelInboundHandler,这个类型接收到入站事件(包括接收到的数据)可以处理应用程序逻辑。当你需要提供响应时,你也可以从 ChannelInboundHandler 冲刷数据。一句话,业务逻辑经常存活于一个或者多个 ChannelInboundHandler。

ChannelPipeline : 保存ChannelHandler和ChannelHandlerContext

  • ChannelPipeline , 用于保存处理过程需要用到的ChannelHandler和ChannelHandlerContext。

ChannelPipeline 提供了一个容器给 ChannelHandler 链并提供了一个API 用于管理沿着链入站和出站事件的流动。每个 Channel 都有自己的ChannelPipeline,当 Channel 创建时自动创建的。 ChannelHandler 是如何安装在 ChannelPipeline? 主要是实现了ChannelHandler 的抽象 ChannelInitializer。ChannelInitializer子类 通过 ServerBootstrap 进行注册。当它的方法 initChannel() 被调用时,这个对象将安装自定义的 ChannelHandler 集到 pipeline。当这个操作完成时,ChannelInitializer 子类则 从 ChannelPipeline 自动删除自身。

ChannelHandlerContext : 上下文

  • ChannelHandlerContext,通信管道的上下文,用于传输业务数据

他们的交互流程是:

1、事件传递给 ChannelPipeline 的第一个 ChannelHandler
2、ChannelHandler 通过关联的 ChannelHandlerContext 传递事件给 ChannelPipeline 中的 下一个ChannelHandler
3、ChannelHandler 通过关联的 ChannelHandlerContext 传递事件给 ChannelPipeline 中的 下一个ChannelHandler

Bootstrap : 建造服务

bootstrap 是我们的 netty 服务建造者, 用于定义启动我们的 netty 服务。

  • ServerBootstrap 用于定义服务端的netty 程序,
  • Bootstrap 用于定义客户端的 netty 程序。

Netty 应用程序通过设置 bootstrap(引导)类的开始,该类提供了一个 用于应用程序网络层配置的容器。

EventLoop : 线程池

EventLoopGroup 是 Netty 内部定一个一个线程池结构, 用于执行来自 netty 内部的事件监听与逻辑处理。

在 EventLoopGroup 中每一个线程为 EventLoop 结构。每个 Channel 会关联一个 EventLoop,用于执行这个 Channel 触发的任务。

EventLoop 用于处理 Channel 的 I/O 操作。一个单一的 EventLoop通常会处理多个 Channel 事件。一个 EventLoopGroup 可以含有多于一个的 EventLoop 和 提供了一种迭代用于检索清单中的下一个。

ChannelFuture : 获取结果

Netty 所有的 I/O 操作都是异步。因为一个操作可能无法立即返回,我们需要有一种方法在以后确定它的结果。出于这个目的,Netty 提供了接口 ChannelFuture,它的 addListener 方法注册了一个 ChannelFutureListener ,当操作完成时,可以被通知(不管成功与否)。

ChannelInitializer

一个特殊的ChannelInboundHandler ,它提供了一种简单的方法来初始化Channel一旦它被注册到它的EventLoop 。 实现最常用于Bootstrap.handler(ChannelHandler)ServerBootstrap.handler(ChannelHandler)ServerBootstrap.childHandler(ChannelHandler)的上下文中,以设置ChannelChannelPipeline



public class MyChannelInitializer extends ChannelInitializer {
    public void initChannel(Channel channel) {
        channel.pipeline().addLast("myHandler", new MyHandler());
    }
}

ServerBootstrap bootstrap = ...;
...
bootstrap.childHandler(new MyChannelInitializer());
...


SimpleChannelInboundHandlerChannelInboundHandlerAdapter 区别:

netty发送和接收数据handler处理器 主要是继承 SimpleChannelInboundHandlerChannelInboundHandlerAdapter

一般用netty来发送和接收数据都会继承SimpleChannelInboundHandlerChannelInboundHandlerAdapter这两个类,那么这两个到底有什么区别呢?

其实用这两个抽象类是有讲究的,在客户端的业务Handler继承的是SimpleChannelInboundHandler,而在服务器端继承的是ChannelInboundHandlerAdapter

最主要的区别就是SimpleChannelInboundHandler在接收到数据后会自动release掉数据占用的Bytebuffer资源(自动调用Bytebuffer.release())。

而为何服务器端不能用呢,因为我们想让服务器把客户端请求的数据发送回去,而服务器端有可能在channelRead方法返回前还没有写完数据,因此不能让它自动release。

  • SimpleChannelInboundHandlerChannelInboundHandlerAdapter的子类 :

  • 继承ChannelInboundHandlerAdapter后,即可收到消息并处理.

public abstract class SimpleChannelInboundHandler<I> extends ChannelInboundHandlerAdapter {

    private final TypeParameterMatcher matcher;
    private final boolean autoRelease;

    /**
     * see {@link #SimpleChannelInboundHandler(boolean)} with {@code true} as boolean parameter.
     */
    protected SimpleChannelInboundHandler() {
        this(true);
    }

    /**
     * Create a new instance which will try to detect the types to match out of the type parameter of the class.
     *
     * @param autoRelease   {@code true} if handled messages should be released automatically by passing them to
     *                      {@link ReferenceCountUtil#release(Object)}.
     */
    protected SimpleChannelInboundHandler(boolean autoRelease) {
        matcher = TypeParameterMatcher.find(this, SimpleChannelInboundHandler.class, "I");
        this.autoRelease = autoRelease;
    }
}    

ChannelInboundHandlerAdapter 的方法:

public class EchoServerHandler extends ChannelInboundHandlerAdapter{
    public void channelRegistered(ChannelHandlerContext ctx) {
        System.out.println("注册");
    }
    public void channelActive(ChannelHandlerContext ctx) {
    	System.out.println("激活");
    }
    public void channelInactive(ChannelHandlerContext ctx) {
    	System.out.println("断开");
    }
    public void channelUnregistered(ChannelHandlerContext ctx) {
    	System.out.println("注销");
    }
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
    	System.out.println("读取消息");
    }
    public void channelReadComplete(ChannelHandlerContext ctx)  {
    	System.out.println("消息读取完成");
    }
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
    	System.out.println("用户事件");
    }
    public void channelWritabilityChanged(ChannelHandlerContext ctx){
    	System.out.println("可写状态变更为"+ctx.channel().isWritable());
    }
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
    	System.out.println("发生异常");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值