Netty教程之NIO基础

NIO

介绍

NIO 全称java non-blocking IO(非阻塞 I/O),后续提供了一系列改进的输入/输出的新特性,被统称为 NIO(即 New IO),是同步非阻塞的。

        阻塞和非阻塞是进程在访问数据的时候,数据是否准备就绪的一种处理方式,当数据没有准备的时候。

阻塞(Block):往往需要等待缓冲区中的数据准备好过后才处理其他的事情,否则一直等待在那里。

非阻塞(Non-Block):当我们的进程访问我们的数据缓冲区的时候,如果数据没有准备好则直接返回,不会等待。如果数据已经准备好,也直接返回

         同步和异步都是基于应用程序和操作系统处理 IO 事件所采用的方式;

同步:应用程序要直接参与 IO 读写的操作,必须阻塞在某个方法上面等待我们的 IO 事件完成

异步:所有的 IO 读写交给操作系统去处理,应用程序只需要等待通知,可以去做其他的事情,并不需要去完成真正的 IO 操作,当操作完成 IO 后,会给我们的应用程序一个通知

特点

1.非阻塞式的I/O操作。这意味着一个线程可以同时管理多个连接,而不必等待每个连接的I/O操作完成

2.通过Channel和Buffer来进行数据传输。Channel表示与实体(文件、套接字等)的连接,而Buffer是用于在Channel和应用程序之间传输数据的缓冲区

3.提供了内存映射文件的功能,可以将文件直接映射到内存中,从而实现了快速的文件I/O操作

4.提供了灵活的缓冲区管理功能,可以方便地进行数据的读取、写入和处理

5.采用了面向块的数据传输方式,可以一次性传输大量数据,提高了I/O操作的效率

运用场景

        适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,弹幕系统,服务器间通讯等

三大组件

NIO的三个最重要的核心分别为:Channel,Buffer和Selector

Channel(通道)

        通道;对原 I/O 包中的流的模拟,到任何目的地(或来自任何地方)的所有数据都必须通过一个 Channel 对象,通道是双向的(一个Channel既可以读数据,也可以写数据)

常见类型:

        FileChannel

        DatagramChannel

        SocketChannel

        ServerSocketChannel

FileChannel主要用于文件传输,其他三种用于网络通信。

Buffer(缓冲区)

缓冲区;实际上是一个容器对象,对数组进行了封装,用数组来缓存数据,还定义了一些操作数组的API,如 put()、get()、flip()、compact()、mark() 等。在NIO中,无论读还是写,数据都必须经过Buffer缓冲区.

        ByteBuffer

                MappedByteBuffer
                DirectByteBuffer
                HeapByteBuffer

        ShortBuffer
        IntBuffer
        LongBuffer
        FloatBuffer
        DoubleBuffer
        CharBuffer
其中最常用的是ByteBuffer

Selector(选择器)

        选择器;是一个特殊的组件,用于采集各个通道的状态(或者事件)

socket连接方法

Socket编程理解为对TCP协议的具体实现。

多线程技术

系统为每一个连接分配一个thread(线程),分别去处理对应的socket连接

缺点:

        1.内存占用高。每有一个socket连接,系统就要分配一个线程去对接。当出现大量连接时,会开辟大量线程,导致占用大量内存。

        2.线程上下文切换成本高

        3.只适合连接数较少的场景

线程上下文切换:
        一个CPU在同一个时刻是只能处理一个线程的,由于时间片耗尽或出现阻塞等情况,CPU 会转去执行另外一个线程,这个叫做线程上下文切换

线程池技术

使用线程池,让线程池中的线程去处理连接

缺点:

        1.在阻塞模式下,线程只能处理一个连接。线程池中的线程获取任务,只有当任务完成/socket断开连接,才会去获取执行下一个任务

        2.只适合短链接的场景

selector技术

为每个线程配合一个选择器,让选择器去管理多个channel。(注:FileChannel是阻塞式的,因此无法使用选择器。)
让选择器去管理多个工作在非阻塞式下的Channel,获取Channel上的事件,当一个Channel没有任务时,就转而去执行别的Channel上的任务。这种适合用在连接多,流量小的场景。

        若事件未就绪,调用 selector 的 select() 方法会阻塞线程,直到 channel 发生了就绪事件。这些事件就绪后,select 方法就会返回这些事件交给 thread 来处理。

ByteBuffer

简单示例

public class TestByteBuffer {
    public static void main(String[] arge){

        try{
            //1.输入输出流,文件数据传输
            FileChannel channel = new FileInputStream("network-program/data.txt").getChannel();

            //2.准备缓冲区,并设置大小
            ByteBuffer buffer = ByteBuffer.allocate(10);

            //3.从channel读取数据,并写入buffer中
            channel.read(buffer);

            //4.buffer切换成读模式
            buffer.flip();

            //5.判断是否还有剩余未读数据
            while (buffer.hasRemaining()){
                byte b = buffer.get();

                System.out.print((char)b);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

使用步骤

1.向buffer写入数据,如:channel.read(buffer);

2.调用flip()切换至读模式

3.从buffer读取数据,如:buffer.get();

4.调用clear()或compact()切换到写模式

属性

        capacity:缓冲区的容量,不可变

        limit:缓冲区的界限。limit之后的数据不允许读写

        position:读写指针。position不可大于limit,且position不为负数

        mark:标记。记录当前position的值。position被改变后,可以通过调用reset() 方法恢复到mark的位置

 常见方法

allocate方法

        通过allocate我们可以给ByteBuffer分配空间,但是这个空间不可以动态变换,如果想要改变ByteBuffer的大小只能重新分配一个

ByteBuffer.allocate(10);

allocateDirect方法

通过allocateDirect我们也可以给ByteBuffer分配空间

ByteBuffer.allocateDirect(10);

allocate 与 allocateDirect的区别:

1.allocate创建出来的是HeapByteBuffer对象,allocateDirect创建出来的是DirectByteBuffer对象

2.HeapByteBuffer是存在于JVM的堆内存中,DirectByteBuffer是存在于直接(系统)内存中

3.HeapByteBuffer的读写效率低于DirectByteBuffer,因为HeapByteBuffer存在于jvm中的,自然会收到垃圾回收器的影响

4.DirectByteBuffer使用不当,容易造成内存泄露

put方法

put方法可以将数据放入到缓冲区中。操作完成后,position的值会+1,并指向下一个可存放的区域,limit=capacity

buffer.put(byte b);

flip方法

flip方法会切换对当前缓冲区的去操作,写/读->读/写

buffer.flip();

当是读模式切换到写模式时,恢复为put时的值。 

get方法

get方法会读取缓冲区里的数据,一次只能读取一个。读取后,position的值会+1,指向下一个可读区。当position大于limit时,会报异常。get方法如果传入指定的索引位置:get(i)。则position的值不会产生变动。

buffer.get();

clear方法

clean方法就像初始化一样,会把ByteBuffer的里属性值都恢复到最初,并且清除缓冲区里的数据。

buffer.clear();

compact方法

compact方法会把已经读取的数据清除,后面未读取的数据向前压缩,然后切换到写模式。
数据前移后,原始位置的数据不会清楚,但是在后面的写入操作中会被覆盖。

buffer.compact();

rewind方法

rewind方法只能在读模式下使用,使用后,会恢复position、limit和capacity的值

buffer.rewind();

mark方法和reset方法

这个两个方法通常都是搭配着使用。
mark做一个标记,会保存当前position的值;reset方法会把mark保存的值重新赋给position。

buffer.mark();

buffer.reset();

字符串与ByteBuffer的相互转换

方法一:

        // 编码:字符串的getByte方法
        ByteBuffer buffer = ByteBuffer.allocate(15);
        buffer.put(str.getBytes());

方法二:

        // 编码:StandardCharsets的encode方法获取ByteBuffer
        ByteBuffer buffer2 = StandardCharsets.UTF_8.encode(str);

方法三:

        ByteBuffer buffer3 = ByteBuffer.wrap(str.getBytes());
        // 解码: 通过StandardCharsets的decoder方法解码
        String decodeStr3 = StandardCharsets.UTF_8.decode(buffer3).toString();

黏包和半包

黏包:发送方在发送数据时,并不是一条一条地发送数据,而是将数据整合在一起,当数据达到一定的数量后再一起发送。这就会导致多条信息被放在一个缓冲区中被一起发送出去。
半包:因为我们分配缓冲区的大小是固定,如果空间小于数据量,那就只能先把当前缓冲区里的数据读取完,再去接收剩下的的数据。数据就会出现被截断的断层现象。

如:

  • Hello world!\n

  • I’m LIKEGAKKI!\n

  • How are you?\n
    经过传输后,服务端的产生了两个ByteBuffer:

  • Hello,world\nI’m LIKEGAKKI\nHo(黏包)

  • w are you?\n?(半包)

重新拆分:

public class TestByteBufferExam {
    public static void main(String[] args){
        ByteBuffer buffer = ByteBuffer.allocate(32);

        buffer.put("Hello,world\nI,m zhangsan\nHo".getBytes());
        split(buffer);
        buffer.put("w are you?\n".getBytes());
        split(buffer);

    }

    private static void split(ByteBuffer buffer){
        buffer.flip();

        for(int i = 0;i<buffer.limit();i++){
            if(buffer.get(i) == '\n'){
                int length = i + 1 - buffer.position();

                ByteBuffer byteBuffer = ByteBuffer.allocate(length);

                for(int j = 0;j<length;j++){
                    byteBuffer.put(buffer.get());
                }

                System.out.println(byteBuffer.get());
            }
        }

        buffer.compact();
    }

在循环中用get(i)方法依次读取数据,当读取的数据匹配‘\n’时,说明之前的读取的是一段信息。

记录该段数据长度,以便于申请对应大小的缓冲区;将缓冲区的数据通过get()方法写入到target中。

调用compact方法切换模式,因为缓冲区中可能还有未读的数据。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

光伏百科|分布式光伏电站如何开展运维管理工作?

随着经济的不断发展和生活水平的日益提高&#xff0c;节能环保已经成为全社会的责任和共识&#xff0c;分布式光伏电站作为清洁能源走进了千家万户。然而&#xff0c;在分布式光伏电站运行期间&#xff0c;面临监管困难、系统繁多、火灾隐患和运维不当等困难&#xff0c;该如何…

2024年【G2电站锅炉司炉】考试及G2电站锅炉司炉找解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 G2电站锅炉司炉考试考前必练&#xff01;安全生产模拟考试一点通每个月更新G2电站锅炉司炉找解析题目及答案&#xff01;多做几遍&#xff0c;其实通过G2电站锅炉司炉复审模拟考试很简单。 1、【多选题】下列为锅炉的…

Python爬虫之爬取网页图片

当我们想要下载网页的图片时&#xff0c;发现网页的图片太多了&#xff0c;无从下手&#xff0c;那我们写一个脚本来爬取呗。 这次的脚本是专门针对某个外国网站使用的&#xff0c;因此仅供参考思路。 在测试的过程中&#xff0c;我发现网站使用了发爬虫机制&#xff0c;具体就…

蓝桥杯-网络安全比赛(2)基础学习-正则表达式匹配电话号码、HTTP网址、IP地址、密码校验

正则表达式&#xff08;Regular Expression&#xff09;&#xff1a;定义&#xff1a;一种强大的文本处理工具&#xff0c;用于描述、匹配和查找字符串中的特定模式。应用&#xff1a;密码验证、文本搜索和替换、数据清洗等。特点&#xff1a;通过特定的元字符和规则来构建复杂…

vcf文件可以用excel打开吗?四种解决方案

vcf文件可以用excel打开吗&#xff1f; 当然可以。 一、VCF文件简介 VCF&#xff08;vCard&#xff09;文件是一种用于存储联系人信息的文件格式。它通常包含姓名、电话号码、电子邮件地址、地址等详细信息。VCF文件在多种设备和操作系统中广泛使用&#xff0c;特别是在电子邮…

2024年【G3锅炉水处理】考试题及G3锅炉水处理考试报名

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 G3锅炉水处理考试题参考答案及G3锅炉水处理考试试题解析是安全生产模拟考试一点通题库老师及G3锅炉水处理操作证已考过的学员汇总&#xff0c;相对有效帮助G3锅炉水处理考试报名学员顺利通过考试。 1、【多选题】锅筒…

【八股】2024春招八股复习笔记2(大数据开发,Java)

【八股】2024春招八股复习笔记2&#xff08;大数据开发&#xff09; 文章目录 1、大数据存储&#xff08;Flume、Hive、HBase、HDFS&#xff09;2、大数据计算&#xff08;MapReduce&#xff0c;Spark、Flink&#xff09;3、大数据集群&#xff08;Yarn、ZooKeeper、kafka&…

部署云原生边缘计算平台kubeedge

文章目录 1、kubeedge架构2、基础服务提供 负载均衡器 metallb2.1、开启ipvc模式中的strictARP2.2、部署metalb2.2.1、创建IP地址池2.2.2、开启二层转发&#xff0c;实现在k8s集群节点外访问2.2.3、测试 3、部署cloudcore3.1、部署cloudcore3.2、修改cloudcore的网络类型 4、部…

二叉树|450.删除二叉搜索树中的节点

力扣题目链接 class Solution { public:TreeNode* deleteNode(TreeNode* root, int key) {if (root nullptr) return root; // 第一种情况&#xff1a;没找到删除的节点&#xff0c;遍历到空节点直接返回了if (root->val key) {// 第二种情况&#xff1a;左右孩子都为空&…

2024年第六届机器人系统与自动化工程国际会议(RSAE 2024)即将召开!

2024年第六届机器人系统与自动化工程国际会议&#xff08;RSAE 2024&#xff09;将于2024年6月21-23日在日本东京召开。RSAE 2024 的主要目标是加强合作&#xff0c;并为院士、专业人士和研究人员提供一个论坛&#xff0c;交流他们的研究成果、创新理念和解决方案&#xff0c;包…

【网络】:数据链路层

数据链路层 一.以太网帧格式二.认识MTU三.ARP协议1.ARP协议的工作流程2.ARP数据报的格式3.ARP欺骗 四.其他重要协议或技术1.DNS2.ICMP协议3.NAT技术&#xff08;重点&#xff09;4.代理服务器 五.一些问题 认识以太网 “以太网” 不是一种具体的网络, 而是一种技术标准; 既包含…

dump文件分析OOM及线程堆栈

OutOfMemoryError (OOM) 如果项目报错&#xff1a; OutOfMemoryError: Java heap space&#xff0c;说明堆内存空间&#xff08;Heap Space&#xff09;中没有足够的空间来分配对象了。 一旦发生 OOM&#xff0c;系统有可能不可用&#xff0c;或者频繁重启。属于非常严重的问题…

聊聊CSS

css 的介绍 学习目标 能够知道css的作用 1. css 的定义 css(Cascading Style Sheet)层叠样式表&#xff0c;它是用来美化页面的一种语言。 没有使用css的效果图 使用css的效果图 2. css 的作用 美化界面, 比如: 设置标签文字大小、颜色、字体加粗等样式。 控制页面布局, 比如…

tensorflow安装以及在Anaconda中安装使用

在遥感领域进行深度学习时&#xff0c;通常使用python进行深度学习&#xff0c;会使用到tensorflow的安装&#xff0c;今天小编就给大家介绍如何在Anaconda中安装tensorflow&#xff01; 下载Anaconda Index of /anaconda/archive/ | 清华大学开源软件镜像站 | Tsinghua Open…

【b站李炎恢】Vue.js Element UI | 十天技能课堂 | 更新中... | 李炎恢

课程地址&#xff1a;【Vue.js Element UI | 十天技能课堂 | 更新中... | 李炎恢】 https://www.bilibili.com/video/BV1U54y127GB/?share_sourcecopy_web&vd_sourceb1cb921b73fe3808550eaf2224d1c155 备注&#xff1a;虽然标题声明还在更新中&#xff0c;但是看一些常用…

netty构建udp服务器以及发送报文到客户端客户端详细案例

目录 一、基于netty创建udp服务端以及对应通道设置关键 二、发送数据 三、netty中的ChannelOption常用参数说明 1、ChannelOption.SO_BACKLOG 2、ChannelOption.SO_REUSEADDR 3、ChannelOption.SO_KEEPALIVE 4、ChannelOption.SO_SNDBUF和ChannelOption.SO_RCVBUF 5、Ch…

任何程序员错过这些宝藏接单平台,都会难过好吗?

财富自由何时才能实现&#xff1f;首先&#xff0c;可以很负责地告诉你&#xff1a;安安心心地当一头牛马肯定是不能&#xff01;兢兢业业十几年&#xff0c;归来仍是马喽。 说实在的&#xff0c;这两年经济下行&#xff0c;互联网红利又日渐褪去。前者既争又抢&#xff0c;后…

【前端学习——js篇】5.事件循环

详细&#xff1a;https://github.com/febobo/web-interview 5.事件循环 js是一种单线程语言&#xff0c;同一时间内只能做一件事情&#xff0c;为了避免单线程阻塞的方法就是事件循环。 在javascript当中&#xff0c;所有的任务都可以分为&#xff1a; 同步任务&#xff1a;按…

【Linux】详解进程终止进程等待

一、页表&&写时拷贝的进一步理解 页表中不仅仅只有虚拟地址到物理地址的映射&#xff0c;还包括了很多选项&#xff0c;其中就包括了映射条目的权限。当我们进程的代码和数据加载到内存并和进程地址空间建立映射关系时&#xff0c;如果数据的内容不允许被修改&#xff…

阿里云服务器多少钱一个月?低至5元1个月

阿里云服务器一个月多少钱&#xff1f;最便宜5元1个月。阿里云轻量应用服务器2核2G3M配置61元一年&#xff0c;折合5元一个月&#xff0c;2核4G服务器30元3个月&#xff0c;2核2G3M带宽服务器99元12个月&#xff0c;轻量应用服务器2核4G4M带宽165元12个月&#xff0c;4核16G服务…