netty的常用类以及执行流程

这篇具有很好参考价值的文章主要介绍了netty的常用类以及执行流程。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

总体概述

类关系

给ServerBootstrap配置两个EventLoopGroup,一个建立连接,一个处理网络io。
EventLoopGroup给EventLoop分配线程。
在 Netty 中,EventLoop 通过不断轮询 Selector 来检测 Channel 上发生的事件,当 Channel 上的事件到达时,EventLoop 会将事件传入 相应的Channel 的成员变量 ChannelPipeline 中,经过所有ChannelHandler 来处理这些事件。

执行流程

当一个事件传入时,会判断是连接事件还是其他事件,如果是连接事件交给eventloopgroup中的建立连接的eventloop,其中的nioserverchannel会处理连接事件,如果是其他事件,那么会交给处理网络io的eventloop中的channel,eventloop轮询发现有channel有事件需要执行,那么就在这个eventloop线程中调用channel的channelpipeline,执行相应的channelhander。

其中:eventloopgroup可以指定eventloop的数量,eventloopgroup就像线程池一样,会负载均衡地分配建立连接的channel给不同的eventloop。

Netty的NIO的常用概念

ServerBootstrap

ServerBootstrap 是一个用于帮助配置和启动服务器的类。它是Netty中用于创建服务器端应用程序的主要入口点

Channel

在计算机网络编程中,Channel(通道) 是一种抽象概念,代表着数据在源和目标之间的连接。通道是数据传输的通路,通道的两端可以是网络连接、文件、套接字等。

Channel类型

  • 文件通道 (FileChannel): 用于对文件进行读写操作。
  • 套接字通道 (SocketChannel, ServerSocketChannel, DatagramChannel): 用于进行网络通信,这些通道是基于 Java NIO 提供的 SelectableChannel 的实现。它们通常通过 EventLoop、ChannelPipeline 和自定义的处理器来实现异步和事件驱动的网络编程。

SocketChannel 是用于 TCP 客户端通信的通道。
它可以连接到远程服务器,并进行双向通信。
SocketChannel 支持阻塞和非阻塞的模式。

ServerSocketChannel 是用于 TCP 服务器通信的通道。
它监听客户端的连接请求,并创建一个新的 SocketChannel 用于与客户端通信。
ServerSocketChannel 也支持阻塞和非阻塞的模式。

DatagramChannel 是用于 UDP 通信的通道。
UDP 是面向消息的,DatagramChannel 支持无连接的数据报传输。
DatagramChannel 与 SocketChannel 相比更轻量,适用于不需要可靠性传输的场景。

  • 管道 (Pipe.SinkChannel, Pipe.SourceChannel): 用于在两个线程之间进行通信。

通道(Channel)和流(Stream)有一些相似之处,但也有一些关键的区别。

相似之处

数据传输: 通道和流都用于在程序和数据源/目的地之间进行数据传输。
字节流和字符流: 通道和流都可以用于处理字节数据(字节流)和字符数据(字符流)。

区别
阻塞非阻塞

通道: 通道通常是非阻塞的,可以使用选择器(Selector)来实现多路复用,从而监控多个通道的状态。
流: 流通常是阻塞的,即在读写操作时,如果没有数据可读或没有足够的空间可写,程序会阻塞等待。

双向性

通道: 通道是双向的,可以支持读和写操作。例如,文件通道 (FileChannel) 可以同时支持读取和写入文件。
流: 流通常是单向的,即要么是输入流(从数据源读取数据),要么是输出流(向数据源写入数据)。需要使用两个流才能实现双向传输。

底层实现

通道: 通道通常直接映射到操作系统的底层 I/O 操作,因此性能可能更好。在 Java NIO 中,通道与 Selector 搭配使用,可以实现非阻塞 I/O。
流: 流通常是在通道的基础上建立的高级抽象,提供了更高层次的 API。在 Java IO 中,流是基于字节或字符的 I/O 操作。

直接缓冲区

在 Java NIO 中,通道(Channel)支持直接缓冲区(DirectBuffer),这使得数据可以直接从内存中的缓冲区传输到通道,或者从通道直接传输到内存中的缓冲区,而不需要中间步骤。
通道: 通道支持直接缓冲区,允许将数据直接从内存中的缓冲区传输到通道,而不需要中间步骤。
流: 流通常不支持直接缓冲区,需要通过中间的数组或缓冲区来进行数据传输。

通常有两种类型的缓冲区:堆缓冲区(Heap Buffer)和直接缓冲区(Direct Buffer)。
堆缓冲区: 在堆上分配的缓冲区,数据位于Java堆内存中。这是默认的缓冲区类型。
直接缓冲区: 直接分配在操作系统的内存中,而不是Java堆中。直接缓冲区可以通过 ByteBuffer.allocateDirect() 方法来创建。
直接缓冲区的优势之一是可以通过 FileChannel 的 transferTo() 和 transferFrom() 方法直接在通道之间传输数据,而无需通过中间缓冲区。
当使用非直接缓冲区(Heap Buffer)时,通常的操作是先将数据从通道读取到堆缓冲区,然后再进行其他操作。同样,当写入时,数据也会从堆缓冲区写入到通道。

Channel内部有成员变量unsafe和Pipeline,unsafe是Channel网络io的底层实现,ChannelPipeline 负责管理该 Channel 上的处理器链。

SelectionKey

简单源码

public interface SelectionKey {
    // 表示对读事件感兴趣
    static final int OP_READ = 1;
    // 表示对写事件感兴趣
    static final int OP_WRITE = 4;
    // 表示对连接事件感兴趣
    static final int OP_CONNECT = 8;
    // 表示对接受事件感兴趣
    static final int OP_ACCEPT = 16;

    // 返回与此键关联的通道
    SelectableChannel channel();

    // 返回选择器
    Selector selector();

    // 返回表示感兴趣的事件的操作集合
    int interestOps();

    // 设置感兴趣的事件的操作集合
    SelectionKey interestOps(int ops);

    // 返回表示已准备就绪的操作的操作集合
    int readyOps();
    。。。。。。。

}

ChannelPipline

ChannelPipline是ChannelHandler的容器,维护了一个Handler的链表和迭代器。
当事件发生时,在eventloop的中它会被传递给ChannelPipeline,然后从头到尾依次经过每个ChannelHandler。
使用ServerBootstrap启动服务器netty会自动为每个Channel创建一个独立的pipepline,我们只要将想用的ChannelHandle加入即可。

ChannelHandler

事务的执行是通过channelpipeline,连接,读写等网络io操作是由channelpipeline的Handler执行(Handler中调用unsafe的方法)。

Eventloop

Eventloop作为NIO框架的Reactor线程,其中有一个Select的成员变量,用来实现多路复用。
Channel需要注册到EventLoop的多路复用器上,EventLoop本质上就是处理网络读写任务的Reactor线程,在Neety中,它还可以用力啊处理定时任务和用户自定义NioTask任务。
Eventloop的run方法是其核心,伪代码:

public void run() {
    while (true) {
        try {
            // 阻塞直到有事件发生
            int readyChannels = selector.select();

            // 处理所有已经就绪的事件
            if (readyChannels > 0) {
                Set<SelectionKey> selectedKeys = selector.selectedKeys();
                for (SelectionKey key : selectedKeys) {
                    if (key.isAcceptable()) {
                        // 处理连接事件
                        // 处理连接事件的逻辑
                    } else if (key.isReadable()) {
                        // 处理读事件
                        // 处理读事件的逻辑
                    } else if (key.isWritable()) {
                        // 处理写事件
                        // 处理写事件的逻辑
                    }
                    // 可以处理更多类型的事件,根据实际需要扩展
                }
                selectedKeys.clear();
            }

            // 处理任务队列中的任务
            while (!tasks.isEmpty()) {
                Runnable task = tasks.poll();
                task.run();
            }
        } catch (IOException e) {
            // 处理异常情况
            e.printStackTrace();
        }
    }

EventGroup

EventLoopGroup 负责管理一组 EventLoop 实例,每个 EventLoop 实例与一个线程相关联。
EventLoopGroup 提供了 shutdownGracefully() 方法,用于优雅地关闭所有关联的 EventLoop。
服务端启动时候,创建了两个NioEventLoopGroup,他们是两个独立的Reactor线程池,一个用来接收客户端的TCP连接,另一个用来处理IO相关的读写操作,或者执行系统Task,定时任务Task等。
接收客户端请求的线程池职责

  1. 接收客户端的TCP连接,初始化Channel参数。
  2. 将链路状态变更事件通知给ChannelPipeline。

处理IO操作的线程池的职责

  1. 异步读取通信数据包,发送读事件给ChannelPipeline;
  2. 异步发送消息,通过发送读事件给ChannelPipeline。
  3. 执行系统Task和定时Task;

Promise和Future

Promise 是 Future 的扩展,它继承了 Future 接口。它们都代表了一个尚未完成的操作,可以用于异步操作的结果通知和处理。
区别:

可写性: Future 是只读的,一旦创建就不能被修改。而 Promise 是可写的,可以通过它来设置操作的结果。
操作结果的设置: 在使用 Future 时,你只能等待其完成,而不能主动设置操作的结果。而在使用 Promise 时,你可以主动设置操作的结果,因此它提供了更灵活的控制。
用途: Future 通常用于表示一个异步操作的结果,而 Promise 用于表示一个异步操作的开始和结果的产生。在很多情况下,你会首先创建一个 Promise,然后将它转化为一个 Future 对象,传递给其他部分的代码,使得它们可以等待异步操作的结果。文章来源地址https://www.toymoban.com/news/detail-823893.html

到了这里,关于netty的常用类以及执行流程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java NIO 和 Netty快速入门

    channel 是读写数据的双向通道,可以从 channel将数据读入buffer,也可以将buffer数据写入channel(较之前的stream要么是输入,要么是输出更为底层) 四种常见Channel: FileChannel DatagramChannel SocketChannel ServerSocketChannel buffer用来缓冲读写数据 常见buffer: ByteBuffer MappedByteBuffer DirectByteBuffer

    2024年02月22日
    浏览(31)
  • 【Netty专题】【网络编程】从OSI、TCP/IP网络模型开始到BIO、NIO(Netty前置知识)

    我是有点怕网络编程的,总有点【谈网色变】的感觉。为了让自己不再【谈网色变】,所以我想过系统学习一下,然后再做个笔记这样,加深一下理解。但是真要系统学习,其实还是要花费不少时间的,所以这里也只是简单的,尽可能地覆盖一下,梳理一些我认为比较迫切需

    2024年02月06日
    浏览(52)
  • 以 Java NIO 的角度理解 Netty

    上篇文章《Netty 入门指南》主要涵盖了 Netty 的入门知识,包括 Netty 的发展历程、核心功能与组件,并且通过实例演示了如何使用 Netty 构建一个 HTTP 服务器。由于 Netty 的抽象程度较高,因此理解起来可能会更加复杂和具有挑战性,所以本文将通过 Java NIO 的处理流程与 Netty 的

    2024年02月12日
    浏览(33)
  • 由浅入深Netty基础知识NIO网络编程

    阻塞模式下,相关方法都会导致线程暂停 ServerSocketChannel.accept 会在没有连接建立时让线程暂停 SocketChannel.read 会在没有数据可读时让线程暂停 阻塞的表现其实就是线程暂停了,暂停期间不会占用 cpu,但线程相当于闲置 单线程下,阻塞方法之间相互影响,几乎不能正常工作,

    2024年02月05日
    浏览(43)
  • Java NIO 图解 Netty 服务端启动的过程

    了解整体Netty常用的核心组件后,并且对比了传统IO模式。在对比过程中,找到了传统IO对应Netty中是如何实现的。最后我们了解到在netty中常用的那些组件。 本文在了解下这些核心组件的前提下,进一步了解组件如何在整个服务器启动过程如何被创建,如何组件之间配合来使

    2024年02月11日
    浏览(30)
  • 【netty基础四】netty与nio

    阻塞I/O在调用InputStream.read()方法时是 阻塞的,它会一直等到数据到来 (或超时)时才会返回; 同样,在调用ServerSocket.accept()方法时,也会一直 阻塞到有客户端连接 才会返回,每个客户端连接成功后,服务端都会启动一个线程去处理该客户端的请求。 阻塞I/O的通信模型示意

    2024年02月10日
    浏览(77)
  • Netty开篇——NIO章下(五)

    SelectionKey 表示 Selector 和网络通道的注册关系,共四种(全是常量): Int OP_ACCEPT:有新的网络连接可以接受,值为 16 (1 4) Int OP_CONNECT: 代表连接已经建立,值为 8 (1 3) Int OP_READ:代表读操作,值为 1 (1 0) Int OP_WRITE: 代表写操作,值为 4  (1 2) 相关方法:   ServerSocket

    2024年01月20日
    浏览(34)
  • Netty开篇——NIO章上(三)

    Java NIO基本介绍 java non-blocking I/O 称为NIO(也叫New IO)。JDK4开始提供,同步非阻塞 相关内容在 java.nio 包及子包下,对java.io 包中的很多类进行改写。 三大核心: Channel(通道),Buffer(缓冲区),Selector(选择器) NIO是 面向缓冲区或者面向块 编程 的 。数据读取到一个它后处理的缓冲区,

    2024年01月16日
    浏览(36)
  • Java NIO FileChannel:BIO与NIO区别、核心组成部分和常用方方法

    深入探讨Java NIO中的FileChannel,包括BIO与NIO的区别、NIO的核心组成部分(Channels、Buffers、Selectors)、FileChannel的常用方法以及示例代码。了解如何使用FileChannel进行文件数据读写操作。

    2024年01月25日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包