Netty前置知识

news2024/11/19 23:29:38

传统IO

这里以文件输入输出流:FileInputStreamFileOutputStream 来进行解释。由继承关系得知,这两个输入和输出类继承自 InputStreamOutputStream 这两个基础的输入、输出的抽象类,这时我们可以看到当我们需要读写文件的时候,就需要创建两个流对象。原理图如下

image-20221221161047776

由图中可以知道,OS 提供了 API 的接口给用户程序调用,这时我们可以将 API 接口和 OS ,比如成 C/S ,也即应用程序就是浏览器端或者桌面端程序, OSAPI 等价于服务器,也即 Controller 接口。

public class FileInputStream extends InputStream {}
public class FileOutputStream extends OutputStream {}

抽象类描述

输入流源码

流程如下:

  1. read(byte b[]) 直接调用 read(byte b[], int off, int len) 函数
  2. 校验 byte 数组是否为空
  3. 校验读取范围是否正确
  4. 校验读取长度
  5. 调用 read() 函数读入一个字节
  6. 验证字节是否达到了文件的末尾
  7. 将该字节的数据保存到 b 数组中
  8. 循环将文件的数据,逐字节的从磁盘中读入放到 b 字节数组中
// 只以文件流为例
public abstract class InputStream implements Closeable {
	public int read(byte b[]) throws IOException {
        return read(b, 0, b.length);  // 直接调用 read(byte b[], int off, int len) 函数
    }
    public int read(byte b[], int off, int len) throws IOException {
        if (b == null) {  // 校验 byte 数组是否为空
            throw new NullPointerException();
        } else if (off < 0 || len < 0 || len > b.length - off) {  // 校验读取范围是否正确
            throw new IndexOutOfBoundsException();
        } else if (len == 0) {  // 校验读取长度
            return 0;
        }
		// 调用 read() 函数读入一个字节
        int c = read();
        if (c == -1) { // 验证字节是否达到了文件的末尾
            return -1;
        }
        b[off] = (byte)c;  // 将该字节的数据保存到 b 数组中

        int i = 1;
        try {
            // 将文件的数据,逐字节的从磁盘中读入放到 b 字节数组中
            for (; i < len ; i++) {
                c = read();
                if (c == -1) {
                    break;
                }
                b[off + i] = (byte)c;
            }
        } catch (IOException ee) {
        }
        return i;
    }

}

输出流源码

流程如下:

  1. write(byte b[]) 直接调用 write(byte b[], int off, int len) 函数
  2. 校验数组不能为空
  3. 校验写入范围是否合理
  4. 校验写入的长度是否为0
  5. 循环将 b 数组中的数据,逐个字节写入文件
public abstract class OutputStream implements Closeable, Flushable {
    public void write(byte b[]) throws IOException {
        write(b, 0, b.length); // 直接调用 write(byte b[], int off, int len) 函数
    }
    public void write(byte b[], int off, int len) throws IOException {
        if (b == null) {  // 校验数组不能为空
            throw new NullPointerException();
        } else if ((off < 0) || (off > b.length) || (len < 0) ||
                   ((off + len) > b.length) || ((off + len) < 0)) {  // 校验写入范围是否合理
            throw new IndexOutOfBoundsException();
        } else if (len == 0) {  // 校验写入的长度是否为0
            return;
        }
        // 循环将 b 数组中的数据,逐个字节写入文件
        for (int i = 0 ; i < len ; i++) {
            write(b[off + i]);
        }
    }
}

文件输入流和输出流复写抽象类方法原理

FileInputStream 复写抽象类方法原理

FileInputStream 流程如下:

  1. read(byte b[]) 方法直接调用 readBytes(byte b[], int off, int len) 方法
  2. read(byte b[], int off, int len) 方法直接调用 readBytes(byte b[], int off, int len) 方法
  3. 可以看到 readBytes(byte b[], int off, int len) 方法为 native ,称之为 JNI (Java Native Interface)方法
public class FileInputStream extends InputStream {
    public int read(byte b[]) throws IOException {
        return readBytes(b, 0, b.length);  // 直接调用 readBytes(byte b[], int off, int len) 方法
    }
    public int read(byte b[], int off, int len) throws IOException {
        return readBytes(b, off, len);  // 直接调用 readBytes(byte b[], int off, int len) 方法
    }
    // 可以看到该方法为 native ,称之为 JNI (Java Native Interface)方法
    private native int readBytes(byte b[], int off, int len) throws IOException;
}

FileOutputStream 复写抽象类方法原理

FileOutputStream 流程如下:

  1. write(byte b[]) 方法直接调用 writeBytes(byte b[], int off, int len, boolean append) 方法
  2. write(byte b[], int off, int len) 方法直接调用 writeBytes(byte b[], int off, int len, boolean append) 方法
  3. 可以看到 writeBytes(byte b[], int off, int len, boolean append) 方法为 native ,称之为 JNI (Java Native Interface)方法
public class FileOutputStream extends OutputStream {
    public void write(byte b[]) throws IOException {
        writeBytes(b, 0, b.length, append);  // 直接调用 writeBytes(byte b[], int off, int len, boolean append) 方法
    }
    public void write(byte b[], int off, int len) throws IOException {
        writeBytes(b, off, len, append); // 直接调用 writeBytes(byte b[], int off, int len, boolean append) 方法
    }
    // 可以看到该方法为 native ,称之为 JNI (Java Native Interface)方法
    private native void writeBytes(byte b[], int off, int len, boolean append) throws IOException;
}

readBytes 方法与 writeBytes 底层实现原理

readBytes 方法,关键流程如下:

  1. malloc 分配一片空间
  2. 调用 read 函数读取数据
  3. 将数据保存放入堆内存的 bytes 数组中

原理图如下所示:

image-20221221175552073

jint readBytes(JNIEnv *env, jobject this, jbyteArray bytes, jint off, jint len, jfieldID fid){
    if(len==0){
        return 0;
    else if (len BUF_SIZE){
        buf = malloc(len); // 分配一片空间
    }
    ...
    if(fd=-1){
        ...
    } else {
        nread=I0_Read(fd, buf, len); // 调用 read 函数读取数据
        if (nread 0){
        // 将数据保存放入堆内存的 bytes 数组中
    	(*env)->SetByteArrayRegion(env, bytes, off, nread, (jbyte *)buf);
        }
        ...
    }
    ...
}

writeBytes 方法,关键流程如下:

  1. 分配一片空间
  2. java 堆内存空间中的 bytes 数组中的内容复制到 buf
  3. buf 中的数据写入到 OS 中

原理图如下所示:

image-20221221180957525

void writeBytes(JNIEnv *env, jobject this, jbyteArray bytes, jint off, jint len, jboolean append, jfieldID fid) {
    ...
    if(len == 0) {
        return;
    } else if (len > BUF_SIZE) {
        buf = malloc(len);  // 分配一片空间
        ...
    }
    ...
    // 将 java 堆内存空间中的 bytes 数组中的内容复制到 buf 中
	(*env)->GetByteArrayRegion(env, bytes, off, len, (jbyte *)buf);
    if (!(*env)->ExceptionOccurred(env)) {
        off = 0;
        ...
        while (1en 0){
            ...
            if (append = JNI_TRUE) {
                ...
            } else {
                n = I0_Write(fd, buf+off, len); // 将 buf 中的数据写入到 OS 中
            }
            ...
        }
    }
    ...
}

NIO 模型

如图所示,如果我们使用普通的 IO 操作,这时我们要完成输入输出对象时,就需要创建两个对象:输入流、输出流,同时我们在传输时面向的数据为字节数据,也即字节流。

image-20221221181255881

这时我们可以引入下图,如图所示,我们可以引入一个新的 IO 模型,这时,不需要再为了传输数据时创建两个对象流,我们只需要在两个通讯的对象之间,构建一个 Channel 抽象通道,将数据抽象为 Buffer ,这时我们只需要双方在该 Channel 通道中传递 Buffer 即可,我们只需要将数据放入 Buffer ,然后在通道之间传递即可。

image-20221221181315967

JVM 内存引入直接内存和堆内存原理

如下图所示,我们以创建一个对象的原理,来引入直接内存和堆内存的原理。我们看到在创建一个对像时,包含创建对象、放置对象的引用、复制对象引用、存放对像引用,为何需要复制?因为 invokespecialastore 这两个字节码需要消耗两个引用,而 new 会返回一个引用,所以我们需要 dup复制一个引用,在创建对像时,需要创建一片空间,该空间如果用 c语言 来描绘,我们可以用 malloc 函数来进行创建该对象空间,同时 free 函数可以释放该空间,在 C++ 中由于引入了面向对象的概念,这时不会使用 malloc 来分配原始内存,引入了 new 操作符和 delete 操作符,new 在用 malloc 分配完内存后,将会调用构造函数和构造初始化列表,delete 会在执行析构函数后,调用 free 来释放空间。

image-20221221182439089

直接内存和堆内存原理

如下图所示,我们可以称:

  1. JVM 内存中分配的空间为: 直接内存缓冲区(DirectByteBuffer
  2. JVM 内存中的堆内存中开辟的空间为:堆内缓冲区(HeapByteBuffer

image-20221221183200750

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

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

相关文章

leetcode--搜索

搜索1.深度优先搜索(DFS)&#xff08;1&#xff09;岛屿的最大面积(695)&#xff08;2&#xff09;省份数量&#xff08;3&#xff09;太平洋大西洋水流问题(417)2.回溯法&#xff08;1&#xff09;全排列(46)&#xff08;2&#xff09;组合(77)&#xff08;3&#xff09;单词搜…

C++ allocator设计内存管理器

文章目录allocator内存管理器基本属性类的设计关键功能的实现完整的内存管理器内存管理器的测试&#xff1a;设计自定义的String类。前情回顾&#xff1a; allocator内存管理类 allocator内存管理器 某些类需要在运行时分配可变大小的内存空间&#xff0c;一般来说我们使用容器…

从零搭建完整python自动化测试框架(UI自动化和接口自动化)

从零搭建完整python自动化测试框架&#xff08;UI自动化和接口自动化&#xff09; 文章目录 总体框架 PO模式、DDT数据驱动、关键字驱动 框架技术选择 框架运行结果 各用例对应的定义方式&#xff08;PO/DDT&#xff09; 测试执行结果 从零开始搭建项目 一、开发环境搭…

泪目,终于有P8大佬把困扰我多年的《计算机网络原理》全部讲明白了

前言 为什么网络协议这么重要呢&#xff1f;集群规模一大&#xff0c;我们首先想到的就是网络互通的问题&#xff1b;应用吞吐量压不上去&#xff0c;我们首先想到的也是网络互通的问题。所以&#xff0c;要成为技术牛人&#xff0c;搞定大系统&#xff0c;一定要过网络这一关&…

Mac怎么清理缓存?这两种方法都非常好用哦

与电脑系统或应用程序非常相似&#xff0c;您的Mac也有自己的系统缓存&#xff0c;它可以在后台临时存储数据&#xff0c;以加快软件安装速度并减少互联网数据使用量&#xff08;通过Apple&#xff09;。与电脑系统或应用程序类似&#xff0c;缓存数据可能会开始堆积——占用存…

unordered系列关联式容器以及哈希表原理实现

Ⅰ. unordered 系列关联式容器 在C98中&#xff0c;STL提供了底层为红黑树结构的一系列关联式容器&#xff0c;在查询时效率可达到 log2nlog_2 nlog2​n&#xff0c;即最差情况下需要比较红黑树的高度次&#xff0c;当树中的节点非常多时&#xff0c;查询效率也不理想。最好的…

Android Studio Profiler 检查内存

Android Studio Profiler 检查内存简单介绍 如何使用&#xff1f; 第一步&#xff1a;点击Profiler按钮 第二步&#xff1a;选择 第三步&#xff1a;选择Capture heap dump 并点击Record 解释相关按钮的功能 垃圾桶按钮&#xff1a;用于强制执行垃圾回收事件的按钮&#xff…

LinkedList(JDK1.8)源码+底层数据结构分析

文章目录前言一、双向链表1.1 双向链表示意图1.2 LinkedList 属性1.3 Node 节点对象二、双向链表的操作2.1 添加元素-add2.2 删除元素-remove2.3 修改元素-set2.4 查询元素-get前言 双向链表是一种数据结构&#xff0c;由若干个节点构成&#xff0c;其中每个节点均由三部分构成…

疯狂游戏笔试题-2022秋招

编程题 1.假设数组第一个元素是k, 如果k在数组内, 则k*21 和 k*31也在数组内. 在已知k的情况下, 需算出另一个数是否也在数组内? 例子: 输入1,2 输出False 输入1,4 输出True 解题思路&#xff1a;暴力&#xff08;doge&#xff09;,实在想不到其它好方法&#xff0c;有…

生成模型详解

一、生成模型的定义 给定的训练集X{x1,x2,...,xn}X \{x^1,x^2,...,x^n\}X{x1,x2,...,xn}隐变量zzz满足p(z)N(0,I)p(z) \mathcal{N} (0,I)p(z)N(0,I)定义一个条件分布pθ(x∣z)p_{\theta}(x|z)pθ​(x∣z)&#xff0c;θ\thetaθ可以理解为生成模型的参数训练好模型后&#xff…

java高校宿舍费缴纳报修管理系统ssm1561

系统选用B/S模式&#xff0c;应用jsp技术&#xff0c; MySQL为后台数据库。系统主要包括个人中心、学生管理、宿管管理、宿舍信息管理、宿舍预订管理&#xff0c;在线报修管理、费用缴纳管理、投诉建议管理、论坛交流、系统管理等功能模块。 本系统采用从上往下的步骤开发&…

爬虫学习-数据解析三种方式:正则、bs4、xpath,以及一些实例操作

若出现乱码page_text page_text.encode(iso-8859-1).decode(gbk)或者查看源码head里面的说明&#xff0c;设置成相同的即可 数据解析原理概述 解析的局部的文本内容都会在标签之间或者标签对应的属性中进行储存数据解析就是 1、进行指定标签的定位2、标签或者标签对应的属性中…

设计模式之美总结(结构型篇)

title: 设计模式之美总结&#xff08;结构型篇&#xff09; date: 2022-12-21 09:59:11 tags: 设计模式 categories:设计模式 cover: https://cover.png feature: false 文章目录1. 代理模式&#xff08;Proxy Design Pattern&#xff09;1.1 原理解析1.2 动态代理1.3 应用场景…

排查Java服务CPU使用率高达100%的原因

排查Java服务CPU使用率高达100%的原因 Java服务在服务器运行一段时间&#xff0c;有一天CPU使用率突然高达100%&#xff0c;通过jstack工具分别在CPU使用率为100%时执行了一次堆线程dump和cpu使用率降下来后执行了一次堆线程dump 目录排查Java服务CPU使用率高达100%的原因一、环…

【SQL】一文详解嵌入式SQL(建议收藏)

&#x1f482;作者简介&#xff1a; THUNDER王&#xff0c;一名热爱财税和SAP ABAP编程以及热爱分享的博主。目前于江西师范大学会计学专业大二本科在读&#xff0c;同时任汉硕云&#xff08;广东&#xff09;科技有限公司ABAP开发顾问。在学习工作中&#xff0c;我通常使用偏后…

SQLMap 扫描利用SQL注入

一、SQLMap介绍 SQLMap 是一个自动化的SQL注入工具&#xff0c;其主要功能是扫描、发现并利用给定URL的SQL注入漏洞&#xff0c;内置了很多绕过插件&#xff0c;支持的数据库是MySQL 、Oracle 、PostgreSQL 、Microsoft SQL Server、Microsoft Access 、IBM DB2, SQ Lite 、Fir…

光伏行业管理亟待变革,数商云供应链系统订单流程自动化流转助力企业降本增效

作为实现“3060”双碳目标的主力军&#xff0c;光伏产业正迎来空前的政策、市场、资本三重加持的红利期。有业内人士预测&#xff0c;到2025年全球新增光伏装机量将达到270-330GW&#xff0c;国内新增光伏装机量将达到90-110GW&#xff0c;十四五期间年均新增光伏装机量将达到7…

用React做一个音乐播放器

介绍 任何正在学习 React 并想使用 React 构建项目的人。有各种博客和文章可以为开发人员指导此类项目。我确实浏览过这些文章&#xff0c;但其中总是缺少一种项目。缺少的项目是音乐播放器和视频播放器。这两个项目都会让您有机会处理音频和视频。您将学到很多东西&#xff0…

Linux学习-97-vmware网络桥接模式配置和vmware快照操作

19.3 vmware网络桥接模式配置 桥接&#xff1a;需要保证Linux虚拟机和本机处在同一个网段&#xff01; #win平台输入ipconfig查看主机的ip地址Linux也必须要配置到对应的网段 桥接模式&#xff1a;主机ip 和虚拟机ip映射到同一块物理网卡&#xff08;光纤&#xff0c;无线…

达梦数据库-centos7安装

参考官方文档 1.环境 操作系统CPU数据库CentOS7x86_64dm8_20221121_x86_rh6_64.iso 2.安装前准备 2.1 关闭防火墙 或 开放5236端口 # 关闭防火墙 systemctl stop firewalld systemctl disable firewalld # 开放5236端口&#xff08;推荐使用&#xff09; firewall-cmd --pe…