Nettyの前置理论篇

news2024/11/25 13:41:48

本篇主要介绍NIO中的三大组件:Channel、Buffer、Selector的理论知识

1、NIO基本概念

        NIO(non-blocking io 或 new io)区别于传统IO,是一种面向缓冲区的非阻塞IO操作,在传统IO中,数据是以字节或字符为单位从流中顺序读写,并且所有的读写操作都是阻塞的。例如,当一个线程调用read()方法时,该线程会被阻塞,直到数据被读入或发生错误。

        NIO相比于传统的IO有以下的特点和优势:

  • 非阻塞IO: NIO允许通道在非阻塞模式下工作,这意味着一个线程可以发起IO操作而不必等待操作完成,从而使得同一个线程可以同时处理多个IO操作。

  • 面向缓冲区: NIO通过缓冲区进行数据的读写操作,而不是直接操作流。这种方式更接近底层操作系统的IO模型,能够提高效率。

  • 多路复用: 通过选择器,一个线程可以监控多个通道的IO事件,如连接请求、读写数据等。这种机制使得NIO非常适合于实现高性能的服务器和网络应用。

        NIO又包含了三大组件:

        缓冲区(Buffer)

        缓冲区是一个容器对象,用于包含特定基本类型的数据。所有的数据都通过缓冲区进行读写操作。常见的缓冲区类型包括:

  • ByteBuffer:字节缓冲区
  • CharBuffer:字符缓冲区
  • IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer:对应于其他基本数据类型的缓冲区

        缓冲区的核心属性包括:

  • Capacity:缓冲区能容纳的数据元素的总数
  • Position:下一个要读取或写入的元素的位置
  • Limit:写入/读取限制
  • Mark:一个备忘位置,通过reset()方法可以恢复到这个位置

        通道(Channel)

        通道类似于传统IO中的流(Stream),但不同的是,通道可以进行双向操作(既可以读也可以写)。通道用于从数据源(如文件、网络套接字)读数据或将数据写入到数据源。

  • 通道可以进行异步读写
  • 通道可以与缓冲区直接交互
  • 通道可以映射到文件、网络套接字等

        常见的通道类型包括:

  • FileChannel:用于文件的通道
  • SocketChannel:用于TCP连接的通道
  • ServerSocketChannel:用于监听TCP连接的通道
  • DatagramChannel:用于UDP连接的通道

        选择器(Selector)

        选择器是Java NIO的核心组件之一,用于管理多个通道的IO事件。通过选择器,一个线程可以处理多个通道的读写事件,从而实现高效的多路复用,如果使用传统的IO:

        假设每个socket连接都要通过新创建一个线程去处理,第一随着连接数的增加,线程的数量势必也会不断增加,第二,如果线程数量大于cpu核心数,会频繁发生上下文切换问题,很影响性能。

        如果采用线程池的方式改进,一个线程可以服务多个socket连接,但是如果在阻塞模式下,线程依旧仅能处理一个 socket 连接。例如一个餐馆服务员面对A,B两个客人,A一直在看菜单,服务员无法利用这段时间去兼顾B。                

2、传统IO面向流和NIO面向缓冲区的区别

        首先面向流是一种逐个字节或字符处理的思想:

        数据是按顺序一个字节一个字节地读取或写入的,像流水一样。处理时不关心数据的整体,只关注当前读取或写入的字节。

        并且读写操作是阻塞的,一个读写操作没有完成,当前线程会一直等待。例如,当你从一个输入流中读取数据时,线程会被阻塞,直到数据被完全读取。

        而面向缓冲区是一种数据块处理的思想:

        数据通过缓冲区(Buffer)批量读取或写入。缓冲区是内存中的一个块,数据在缓冲区中处理,然后通过通道(Channel)整体读入或写出。

        通道可以配置为非阻塞模式,允许线程在数据还未准备好时继续执行其他操作。例如,使用选择器(Selector)来管理多个通道,一个线程可以处理多个连接。

3、通道(Channel)和缓冲区(Buffer)的联系

        缓冲区在读写操作过程中会维护三个关键属性:position(指针)、limit(限制)和capacity(容量)。        

  • position:指示下一个要读取或写入的元素位置。
  • limit:在读模式下,limit表示缓冲区可读数据的大小;在写模式下,limit表示缓冲区总的容量。
  • capacity:缓冲区的总大小,在缓冲区创建时设定,不可改变。(不同于集合,没有扩容机制)

        在获取缓冲区实例时,通常需要指定容量,假设我们指定的容量是10:

        然后向缓冲区放入了4个字节的数据:

        通过filp方法切换至读取模式,此时position指针代表的是当前从索引为几的地方开始读,limit也变成了可以最多读取多少个元素。

        在读取了4个字节后:

        最后调用clear方法切换回写入模式:(clear会清除所有元素)

        compact方法是将未读完的元素向前压缩,然后切换至写模式

        那么数据是如何在通道和缓冲区之间进行读写操作的呢?

        读操作:当从通道读取数据时,数据被读入到缓冲区中。

  1. 调用通道的read方法,将数据从通道读取到缓冲区。
  2. 使用缓冲区的filp方法切换到读取模式。
  3. 从缓冲区中读取数据。

        写操作:当向通道写入数据时,数据从缓冲区写入到通道中。

  1. 将数据放入缓冲区。
  2. 使用缓冲区的clear() 或 compact() 方法切换到写入模式。
  3. 调用通道的write方法,将数据从缓冲区写入到通道。

        总结:

  • 通道是数据传输的载体,负责从数据源读取数据或将数据写入数据源。
  • 缓冲区是数据的临时存储区,用于存放从通道中读入的数据或将要写入通道的数据。

4、选择器(Selector)是如何实现多路复用

        在学习选择器(Selector)是如何实现多路复用前,首先需要了解一下什么是多路复用:

        使用一个单独的线程同时处理多个I/O操作,而不需要为每个I/O流创建单独的线程或进程,其关键点在于,通过在一个线程中管理多个连接,避免线程创建和上下文切换的开销,并且系统监视多个I/O流,当某个流就绪时(如有数据可读、可以写入等),会通知应用程序处理这个流上的I/O事件。同时/O操作不会阻塞进程或线程,可以同时处理多个I/O请求。

        选择器(Selector)实现多路复用,一般需要分为以下几步:

  1. 将通道(Channel)配置为非阻塞模式,然后注册到选择器上,注册时需要指定需要被监视的事件类型,如连接事件、读事件、写事件。
  2. 选择器通过select()方法轮询已注册通道的I/O事件。select()方法会阻塞,直到至少有一个通道准备好进行I/O操作(如有数据可读)。一旦有通道就绪,选择器返回已就绪通道的集合,这些通道可以进行I/O操作。
  3. 程序通过迭代已就绪通道的集合,逐个处理每个通道的I/O事件。
  4. 根据通道的事件类型(如读就绪、写就绪),执行相应的I/O操作。

        在第一步中,所有通道都被配置为非阻塞模式,这意味着I/O操作不会阻塞线程。如果通道当前没有数据可读或不能写入,操作会立即返回而不会阻塞

        在第二步中,选择器使用事件通知机制,监视所有注册通道的状态。当一个或多个通道的状态发生变化(如有数据可读),选择器会通知应用程序。

什么是事件通知机制?

简单来说,每个注册通道在选择器中都有一个对应的键(SelectionKey),键中记录了通道和事件类型,选择器内部维护一个键集合(Key Set),包含所有注册通道的键和事件类型,选择器在轮询时更新键集合,将就绪通道的键放入已就绪键集合(Ready Key Set)。这样选择器在每次轮询时,只处理已就绪通道的I/O事件,未就绪通道不做处理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1805970.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DevExpress Installed

一、What’s Installed 统一安装程序将DevExpress控件和库注册到Visual Studio中,并安装DevExpress实用工具、演示应用程序和IDE插件。 Visual Studio工具箱中的DevExpress控件 Visual Studio中的DevExpress菜单 Demo Applications 演示应用程序 Launch the Demo…

【栈】895. 最大频率栈

本文涉及知识点 栈 LeetCode895. 最大频率栈 设计一个类似堆栈的数据结构,将元素推入堆栈,并从堆栈中弹出出现频率最高的元素。 实现 FreqStack 类: FreqStack() 构造一个空的堆栈。 void push(int val) 将一个整数 val 压入栈顶。 int pop() 删除并返…

每天壁纸不重样~下载必应每日图片

下载必应每日图片 必应不知道你用过没有你下载过必应的图片没有你又没搜索过桌面图片你是不是安装过桌面图片软件你是不是为找一个好看的图片下载过很多桌面软件 必应每日图片 必应每天都会有一张不同的风景图片,画质清晰,而且不收费可以下载使用 但…

解决Win10系统ping不通、无法远程的问题

1、概述 某天要使用微软的远程桌面程序mstsc.exe远程到旁边的一台测试电脑上,结果远程不了,ping都ping不通,于是详细研究了这个问题。在此大概地记录一下该问题排查的过程,以供参考。 2、ping不通 使用mstsc.exe远程到测试电脑,远程不了,没有反应。于是手动ping一…

IDEA创建Mybatis项目

IDEA创建Mybatis项目 第一步:创建库表 -- 创建数据库 create database mybatis_db;-- 使用数据库 use mybatis_db;-- 创建user表 CREATE TABLE user (id INT AUTO_INCREMENT PRIMARY KEY,username VARCHAR(50) NOT NULL,password VARCHAR(50) NOT NULL,email VARC…

【WP|9】深入解析WordPress [add_shortcode]函数

add_shortcode 是 WordPress 中一个非常强大的函数,用于创建自定义的短代码(shortcodes)。短代码是一种简洁的方式,允许用户在内容中插入动态的、可重用的功能。通过 add_shortcode,开发者可以定义自己的短代码&#x…

里卡提方程(Riccati Equation)例子

里卡提方程(Riccati Equation) 里卡提方程(Riccati Equation)在人形机器人控制中有重要的应用,特别是在最优控制和估计问题中。里卡提方程主要用于求解线性二次型调节器(LQR, Linear Quadratic Regulator)和卡尔曼滤波器(Kalman Filter)。这些方法有助于提高机器人控…

物联网开发tcp协议之——netty拆包问题

1.前言 tcp协议是物联网开发中比较常见的一种通信协议,而netty则是一tcp通信协议中一个比较优秀的框架。tcp协议是一种长连接的协议,是流式传输的,开发过程中最长遇见的问题就是拆包粘包问题。我目前对接过的物联网系列有智能家居设备&#…

8.2 Go 导入与导出

💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

【清华大学】《自然语言处理》(刘知远)课程笔记 ——NLP Basics

自然语言处理基础(Natural Language Processing Basics, NLP Basics) 自然语言处理( Natural Language Processing, NLP)是计算机科学领域与人工智能领域中的一个重要方向。它研究能实现人与计算机之间用自然语言进行有效通信的各种理论和方法。自然语言…

雷电模拟器中控实现,直通源码

目录 前言 开发 需求 初始环境 UI搭建 功能实现 前言 本篇为易语言雷电模拟器中控项目实现操作,一般用于:脚本开发多线程模拟操作等起始模板框架,使用易语言原因为其前后端一体化,对于脚本开发而言更为方便。 开发 需求 以…

Python爬虫入门与登录验证自动化思路

1、pytyon爬虫 1.1、爬虫简介 Python爬虫是使用Python编写的程序,可以自动访问网页并提取其中的信息。爬虫可以模拟浏览器的行为,自动点击链接、填写表单、进行登录等操作,从而获取网页中的数据。 使用Python编写爬虫的好处是,…

[数据集][目标检测]足球场足球运动员身份识别足球裁判员数据集VOC+YOLO格式312张4类别

数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):312 标注数量(xml文件个数):312 标注数量(txt文件个数):312 标注类别…

LeetCode | 1624.两个相同字符之间的最长子字符串

这道题拿到手想法就是去双重遍历暴力解,对于每个字符,从后往前遍历字符串,找到从后往前一直到本次遍历的这个字符串这段子串中和这个字符串相同的字符位置,然后得到子字符串的长度,和ans存储的值做一个比较&#xff0c…

umap降维,c++用法纪实

全是血泪&#xff0c;可惜对于大量数据&#xff0c;速度还是太慢。 一、代码 // ConsoleApplication2.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 //#include <iostream>#include "knncolle/knncolle.hpp" #include "Umap.…

MSPM0l1306——配置滴答定时器

我们配置好了滴答定时器之后&#xff0c;还要手动编写滴答定时器的中断服务函数&#xff0c;因为我们开启的滴答定时器的中断&#xff0c;当滴答定时器的计数值从我们设置的值减到0时&#xff0c;就会触发一次中断&#xff0c;触发中断就会执行中断服务函数。各个中断的中断服务…

Bio-Info每日一题:Rosalind-05-Computing GC Content

&#x1f389; 进入生物信息学的世界&#xff0c;与Rosalind一起探索吧&#xff01;&#x1f9ec; Rosalind是一个在线平台&#xff0c;专为学习和实践生物信息学而设计。该平台提供了一系列循序渐进的编程挑战&#xff0c;帮助用户从基础到高级掌握生物信息学知识。无论你是初…

python开发扑克牌游戏

用一个列表保存54张扑克牌&#xff0c;先洗牌,再按斗地主的发牌方式把牌发给三个玩家&#xff0c;多的3张牌给第一个玩家(地主)最后把每个玩家手上的牌显示出来。 import random# 定义卡牌列表 cards [] # 定义花色列表 suites [黑桃, 红心, 草花, 方块] # 定义点数列表 fac…

牛客热题:最长公共子序列Ⅱ

&#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;力扣刷题日记 &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&#x1f349;留言 文章目录 牛客热题&#xff1a;最长公共子序列Ⅱ题目链接方法一…

QT串口调试助手V2.0(源码全开源)--上位机+多通道波形显示+数据保存(优化波形显示控件)

首先关于Qt的安装和基本配置这里就不做重复说明了&#xff0c;注&#xff1a;本文在Qt5.14基础上完成 完整的项目开源仓库链接在文章末尾 图形控件——qcustomplot QCustomPlot是一个基于Qt框架的开源绘图库&#xff0c;用于创建高质量的二维图表和数据可视化。 QCustomPlot…