当前位置: 首页 > news >正文

NIO核心依赖多路复用小记

NIO允许一个线程同时处理多个连接,而不会因为一个连接的阻塞而导致其他连接被阻塞。核心是依赖操作系统的多路复用机制。

操作系统的多路复用机制

多路复用是一种操作系统的 I/O 处理机制,允许单个进程(或线程)同时监视多个输入或输出流的就绪状态。这样,一个进程就能够通过一个系统调用来等待多个事件,而不是为每个事件创建一个独立的进程或线程。

多路复用常见机制

  1. select: select 是一个系统调用,通过它可以同时监视多个文件描述符(通常是套接字)。当其中任何一个文件描述符准备好进行读取或写入时,select 就会返回,并告诉程序哪些文件描述符处于就绪状态。

  2. poll: poll 也是一个系统调用,它和 select 类似,但是对文件描述符的管理更加灵活,而且没有文件描述符数目的限制。

  3. epoll: epoll 是 Linux 中引入的一种多路复用机制,相对于 selectpoll 具有更好的性能。epoll 使用事件通知的方式,只关心那些发生了变化的文件描述符,减少了遍历全部文件描述符的开销。

网络请求的流程

当客户端请求到达服务器时,整个流程可以分为以下几个步骤,涉及用户态和内核态的协同工作:

  1. 服务器启动: 服务器程序在用户态中启动,并创建一个监听 socket。这个监听 socket 负责接收客户端的连接请求。

  2. 监听连接: 服务器使用 select 或其他多路复用的系统调用,将监听 socket 添加到文件描述符集合中,然后阻塞等待事件发生。这时用户程序告诉内核要监听哪些文件描述符,而这些文件描述符通常是由 accept 等系统调用返回的新连接。

  3. 客户端连接: 当有客户端发起连接请求时,内核接收到连接请求,然后将新的连接 socket(客户端连接的文件描述符)添加到文件描述符集合中。此时内核通知用户程序,有文件描述符就绪。

  4. 处理连接: 用户程序从 select 返回后,检查文件描述符集合,确定哪些连接处于就绪状态。然后,用户程序可以通过 accept 接受新的连接,获得新的文件描述符,并处理与客户端的通信。

下面是一个简化的伪代码示例:

// 服务器启动
int listen_fd = create_and_bind_socket(port);
listen(listen_fd, SOMAXCONN);// 设置监听 socket 到文件描述符集合
fd_set master_fds;
FD_ZERO(&master_fds);
FD_SET(listen_fd, &master_fds);
int max_fd = listen_fd;while (true) {fd_set read_fds = master_fds;// 使用 select 监听文件描述符int ready = select(max_fd + 1, &read_fds, NULL, NULL, NULL);if (ready == -1) {// 处理错误} else {// 检查文件描述符集合,确定哪些连接就绪for (int i = 0; i <= max_fd; ++i) {if (FD_ISSET(i, &read_fds)) {if (i == listen_fd) {// 有新连接int new_fd = accept(listen_fd, ...);FD_SET(new_fd, &master_fds);if (new_fd > max_fd) {max_fd = new_fd;}} else {// 有数据可读handle_data(i);}}}}
}

在这个示例中,listen_fd 是监听 socket 的文件描述符,当有新的连接到达时,会使用 accept 获得新的文件描述符,然后将其添加到文件描述符集合中。select 会在有文件描述符就绪时返回,用户程序通过检查文件描述符集合确定哪些连接可以进行处理。

这个监听 socket 并不是客户端的连接请求,而是用于接受客户端连接的准备工作。客户端连接请求是在客户端发起连接时生成的。

文件描述符

在类Unix/Linux系统中,一切皆文件,包括网络连接。

文件描述符(File Descriptor)是用于标识已打开文件或I/O资源的整数。对于网络连接,文件描述符是内核用于跟踪每个连接的标识符。当一个客户端连接到服务器时,内核为这个连接分配一个文件描述符,通过这个文件描述符,内核能够管理和操作与客户端之间的I/O操作。

连接的表示

在 Linux 系统下,客户端与服务器之间的连接通常被抽象为文件描述符。这是因为内核为每个连接分配了一个文件描述符,通过这个文件描述符可以进行对应连接的读、写等I/O操作。文件描述符是一种通用的抽象,通过它,可以使用相同的接口进行文件、网络连接等各种I/O操作。

文件描述符(File Descriptor)并不是一个真正的文件

在 Linux 下,文件描述符(File Descriptor)并不是一个真正的文件,而是一个整数,用于标识已打开文件或 I/O 资源。每个客户端连接到服务器时,内核会为该连接分配一个文件描述符。这个文件描述符在内核中用于跟踪和管理该连接的相关信息,包括读写数据等 I/O 操作。
Linux 内核并不会创建一个真正的文件来存放客户端的请求内容、客户端的 IP 和端口等信息。相反,它在内核中维护了一个数据结构来表示每个连接的状态,这个数据结构包含了与连接相关的信息。这个信息通常被称为 socket(套接字),是用于在网络上进行通信的抽象。
当客户端发起连接时,内核会分配一个 socket,并分配一个文件描述符用于标识这个 socket。该文件描述符被传递给用户程序,用户程序可以通过这个文件描述符进行对应连接的读写操作。客户端的 IP 地址和端口等信息通常可以通过相应的系统调用获取,而不是通过创建一个文件。
总之,Linux 中的文件描述符不是一个实际的文件,而是用于标识和操作已打开的 I/O 资源,其中包括网络连接。相关的信息则在内核中以 socket 的形式存在,而不是在文件中。

用户态和内核态

在操作系统中,用户态(User Mode)和内核态(Kernel Mode)是指操作系统与应用程序之间的两个不同的运行级别或权限级别。这两个模式之间的切换是由操作系统内核控制的,而且涉及到处理器的特权级别。

  1. 用户态(User Mode):

    • 在用户态运行的是应用程序代码。在这个级别下,应用程序只能访问自己的内存空间,不能直接访问操作系统的内核空间。
    • 用户态的应用程序不能执行一些特权指令,例如直接访问硬件设备或执行特定的系统管理任务。
  2. 内核态(Kernel Mode):

    • 内核态是操作系统内核运行的级别。在这个级别下,操作系统具有较高的特权,可以执行所有指令,包括直接访问硬件设备、修改系统控制寄存器等。
    • 操作系统内核负责管理系统的资源,处理中断、异常和系统调用,以及执行一些特权操作。
  3. 切换:

    • 当应用程序需要执行一些特权操作(例如打开一个文件、发送网络数据等)时,就需要从用户态切换到内核态。这个切换是通过系统调用(System Call)来触发的。
    • 当发生中断、异常或系统调用时,处理器会从用户态切换到内核态,执行相应的内核代码。完成后,再切换回用户态继续执行应用程序代码。
  4. 切换的目的:

    • 切换到内核态的目的是为了执行一些需要较高权限或操作系统特权的任务,例如管理系统资源、执行设备驱动程序等。
    • 切换回用户态后,应用程序可以继续执行。这种切换的目的是为了保护系统的安全性和稳定性,防止应用程序直接访问敏感的系统资源。

总的来说,用户态和内核态的划分是为了保障系统的安全性和稳定性,确保应用程序不能随意访问和修改系统的关键资源。用户态和内核态之间的切换是由操作系统内核控制的,它会根据需要在两者之间进行切换。

文件描述符集合

在用户态,通过 select 系统调用的参数中的文件描述符集合(通常是 fd_set)来告诉内核要监听哪些文件描述符。fd_set 是一个数据结构,它使用一个位图来表示文件描述符的状态,每个位表示一个文件描述符。

在调用 select 时,用户程序会将自己关心的文件描述符添加到 fd_set 中。在 select 返回后,用户程序可以检查 fd_set 来确定哪些文件描述符处于就绪状态。就绪状态通常表示有数据可读、有数据可写或者发生了错误。

下面是一个简化的示例:

#include <sys/select.h>int main() {fd_set read_fds;FD_ZERO(&read_fds);int sockfd = /* 创建并设置socket描述符 */;FD_SET(sockfd, &read_fds);// 设置超时时间为5秒struct timeval timeout;timeout.tv_sec = 5;timeout.tv_usec = 0;// 调用select,监听文件描述符int ready = select(sockfd + 1, &read_fds, NULL, NULL, &timeout);if (ready == -1) {// 处理错误} else if (ready == 0) {// 超时} else {// 检查read_fds,确定哪些文件描述符就绪if (FD_ISSET(sockfd, &read_fds)) {// sockfd 就绪,可以进行读操作}}return 0;
}

在这个示例中,通过 FD_SETsockfd 添加到 read_fds 中,然后调用 select 来监听这个文件描述符。当 select 返回后,通过检查 FD_ISSET 可以确定 sockfd 是否处于就绪状态,进而进行相应的操作。

用户程序在调用 select 之前,需要设置好相应的文件描述符集合,并在 select 返回后,根据就绪状态进行处理。这种方式允许用户程序选择性地监听和处理多个文件描述符。

学习打卡:Java学习笔记-day04-NIO核心依赖多路复用小记

相关文章:

NIO核心依赖多路复用小记

NIO允许一个线程同时处理多个连接&#xff0c;而不会因为一个连接的阻塞而导致其他连接被阻塞。核心是依赖操作系统的多路复用机制。 操作系统的多路复用机制 多路复用是一种操作系统的 I/O 处理机制&#xff0c;允许单个进程&#xff08;或线程&#xff09;同时监视多个输入…...

如何彻底卸载 Microsoft Edge?

关闭 Microsoft Edge 浏览器和所有正在运行的进程。 按下 Ctrl Shift Esc 键打开任务管理器。在任务管理器中&#xff0c;找到所有正在运行的 Microsoft Edge 进程。右键单击每个进程&#xff0c;然后选择“结束任务”。 导航至 Microsoft Edge 的安装目录。 默认情况下&…...

JavaScript-对象-笔记

1.字面量创建对象、对象的使用 对象就是一组 属性和方法的集合 属性&#xff1a; 特征 相当于变量 静态 是什么 方法&#xff1a; 行为 相当于函数 动态 干什么 创建对象 创建对象的第一种&#xff1a;使用字面量 {} 对象中的元素是键值对 使用逗号隔开 键:值 的形式 var 对象名…...

java 运算符 选择语句

1&#xff1a;运算符 运算符&#xff1a;对字面量或者变量进行操作的符号 表达式&#xff1a;用运算符把字面量或者变量连接起来符合java语法的式子就可以称为表达式。不同运算符连接的表达式体现的是不同类型的表达式。 举例说明&#xff1a;** int a 10; int b 20; in…...

CNN:Convolutional Neural Network(上)

目录 1 为什么使用 CNN 处理图像 2 CNN 的整体结构 2.1 Convolution 2.2 Colorful image 3 Convolution v.s. Fully Connected 4 Max Pooling 5 Flatten 6 CNN in Keras 原视频&#xff1a;李宏毅 2020&#xff1a;Convolutional Neural Network 1 为什么使用…...

将Android应用修改为鸿蒙应用的工作

将Android应用修改为鸿蒙&#xff08;HarmonyOS&#xff09;应用需要进行一系列主要的工作。以下是在进行这一转换过程中可能需要进行的主要工作&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 1.项目…...

03 Strategy策略

抽丝剥茧设计模式 之 Strategy策略 - 更多内容请见 目录 文章目录 一、Strategy策略二、Comparable和Comparator源码分析使用案例Arrays.sort源码Collections.sort源码Comparable源码Comparator源码 一、Strategy策略 策略模式是一种设计模式&#xff0c;它定义了一系列的算法…...

Python实现分位数回归模型(quantreg算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 分位数回归是简单的回归&#xff0c;就像普通的最小二乘法一样&#xff0c;但不是最小化平方误差的总和…...

【ROS2简单例程】基于python的发布订阅实现

1、自定义消息类型Student 1.1 创建base_interfaces_demo包 1.2 创建Student.msg文件 string name int32 age float64 height 1.2 在cmakeLists.txt中增加如下语句 #增加自定义消息类型的依赖 find_package(rosidl_default_generators REQUIRED) # 为接口文件生成源代码 ro…...

【期末考试】数据库综合复习宝典

目录 第一章 数据库系统概述 第二章 关系代数 第四章 关系数据库理论 第五章 数据库设计 第六章 数据库管理系统 第八章 事务管理 第一章 数据库系统概述 1.1三级模式 ①外模式&#xff1a;它为特定的应用程序或用户群体提供了一个数据视图&#xff0c;这个视图是独立于…...

OpenHarmony南向之LCD显示屏

OpenHarmony南向之LCD显示屏 概述 LCD&#xff08;Liquid Crystal Display&#xff09;驱动&#xff0c;通过对显示器上下电、初始化显示器驱动IC&#xff08;Integrated Circuit&#xff09;内部寄存器等操作&#xff0c;使其可以正常工作。 HDF Display驱动模型 LCD器件驱…...

核心笔记-短篇

接口管理平台:yapi 对象拷贝:Spring Bean 提供的 BeanUtils;hutool-core 提供的 BeanUtil 获得用户设备的信息:导入 UserAgentUtils 依赖;创建 UserAgent 对象使用 加密工具:DigestUtils,Spring Core 提供,静态方法:md5DigestAsHex(byte[]) 客户端编程工具包:HttpCli…...

系统学习Python——警告信息的控制模块warnings:为新版本的依赖关系更新代码

分类目录&#xff1a;《系统学习Python》总目录 在默认情况下&#xff0c;主要针对Python开发者&#xff08;而不是Python应用程序的最终用户&#xff09;的警告类别&#xff0c;会被忽略。 值得注意的是&#xff0c;这个“默认忽略”的列表包含DeprecationWarning&#xff08…...

爬虫的基本原理

基本原理 可以把网页与网页之间的链接关系比作节点中的连线&#xff0c;爬虫可以根据网页中的关系获取后续的网页&#xff0c;当整个网站涉及的页面全部被爬虫访问到后&#xff0c;网站的数据就被访问下来了。 1.爬虫概述 简单点讲&#xff0c;爬虫就是获取网页并提取和保存信…...

MySQL核心SQL

一.结构化查询语言 SQL是结构化查询语言&#xff08;Structure Query Language&#xff09;&#xff0c;它是关系型数据库的通用语言。 SQL 主要可以划分为以下 3 个类别&#xff1a; DDL&#xff08;Data Definition Languages&#xff09;语句 数据定义语言&#xff0c;这…...

关于 setData 同步异步的问题

小程序官方文档中的回答解释: 所以大概意思就是: 1.setData在逻辑层的操作是同步&#xff0c;因此this.data中的相关数据会立即更新,比如下面的例子: const a 1 this.setData({b: a ? a : , }) console.log(that.data.b) // 1 2. setData在视图层的操作是异步&#xff0c;…...

Centos创建一个Python虚拟环境

在 CentOS 上创建一个 Python 虚拟环境&#xff0c;可以使用 virtualenv 工具。以下是创建和激活虚拟环境的基本步骤&#xff1a; 1.安装virtualenv 如果还没有安装 virtualenv&#xff0c;可以使用以下命令安装&#xff1a; sudo yum install python3-virtualenv请注意&…...

怎么使用好爬虫IP代理?爬虫代理IP有哪些使用技巧?

在互联网时代&#xff0c;爬虫技术被广泛应用于数据采集和处理。然而&#xff0c;在使用爬虫技术的过程中&#xff0c;经常会遇到IP被封禁的问题&#xff0c;这给数据采集工作带来了很大的困扰。因此&#xff0c;使用爬虫IP代理成为了解决这个问题的有效方法。本文将介绍如何使…...

C#,字符串匹配算法(模式搜索)Z算法的源代码与数据可视化

Z算法也是模式搜索&#xff08;Pattern Search Algorithm&#xff09;的常用算法。 本文代码的运算效果&#xff1a; 一、Z 算法 线性时间模式搜索算法的Z算法&#xff0c;在线性时间内查找文本中模式的所有出现。 假设文本长度为 n&#xff0c;模式长度为 m&#xff0c;那么…...

强化学习actor-critic

...

React 第五十五节 Router 中 useAsyncError的使用详解

前言 useAsyncError 是 React Router v6.4 引入的一个钩子&#xff0c;用于处理异步操作&#xff08;如数据加载&#xff09;中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误&#xff1a;捕获在 loader 或 action 中发生的异步错误替…...

rknn优化教程(二)

文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK&#xff0c;开始写第二篇的内容了。这篇博客主要能写一下&#xff1a; 如何给一些三方库按照xmake方式进行封装&#xff0c;供调用如何按…...

【位运算】消失的两个数字(hard)

消失的两个数字&#xff08;hard&#xff09; 题⽬描述&#xff1a;解法&#xff08;位运算&#xff09;&#xff1a;Java 算法代码&#xff1a;更简便代码 题⽬链接&#xff1a;⾯试题 17.19. 消失的两个数字 题⽬描述&#xff1a; 给定⼀个数组&#xff0c;包含从 1 到 N 所有…...

系统设计 --- MongoDB亿级数据查询优化策略

系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log&#xff0c;共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题&#xff0c;不能使用ELK只能使用…...

linux arm系统烧录

1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 &#xff08;忘了有没有这步了 估计有&#xff09; 刷机程序 和 镜像 就不提供了。要刷的时…...

HTML前端开发:JavaScript 常用事件详解

作为前端开发的核心&#xff0c;JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例&#xff1a; 1. onclick - 点击事件 当元素被单击时触发&#xff08;左键点击&#xff09; button.onclick function() {alert("按钮被点击了&#xff01;&…...

select、poll、epoll 与 Reactor 模式

在高并发网络编程领域&#xff0c;高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表&#xff0c;以及基于它们实现的 Reactor 模式&#xff0c;为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。​ 一、I…...

在WSL2的Ubuntu镜像中安装Docker

Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包&#xff1a; for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...

【JavaWeb】Docker项目部署

引言 之前学习了Linux操作系统的常见命令&#xff0c;在Linux上安装软件&#xff0c;以及如何在Linux上部署一个单体项目&#xff0c;大多数同学都会有相同的感受&#xff0c;那就是麻烦。 核心体现在三点&#xff1a; 命令太多了&#xff0c;记不住 软件安装包名字复杂&…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...