Java学习笔记-day04-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 返回后,根据就绪状态进行处理。这种方式允许用户程序选择性地监听和处理多个文件描述符。

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

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

相关文章

C++:通过erase删除map的键值对

map是经常使用的数据结构,erase可以删除map中的键值对。 可以通过以下几种方式使用erase 1.通过迭代器进行删除 #include <iostream> #include <map> #include <string> using namespace std;void pMap(const string& w, const auto& m) {cout&l…

Linux第5步_测试虚拟机网络连接

安装好VMwareTools后&#xff0c;就可以测试虚拟机网络连接了&#xff0c;目的是实现虚拟机上网。 1、打开“控制面板”&#xff0c;得到下图&#xff1a; 2、双击“网络和 Internet” &#xff0c;得到下图&#xff1a; 3、双击“网络和共享中心” 4、点击“更改适配器设置”…

rime中州韵小狼毫 中英互绎 滤镜

英文在日常生活中已经随处可见&#xff0c;我们一般中英互译需要使用专业的翻译软件来实现。但如果我们在输入法中&#xff0c;在输入中文的时候&#xff0c;可以顺便瞟一眼对应的英文词汇&#xff0c;或者在输入英文的时候可以顺便了解对应的中文词汇&#xff0c;那将为我们的…

linux网络配置

一、查看Linux基础得网络设置 1.网关——route -n 2.IP地址——ifconfig 或 ip a ethtool -p ens33 让ens33网卡快速闪烁&#xff0c;分辨网线对应哪个网卡 3.DNS服务器——cat /etc/resolv.conf 4.主机名——hostname 5.路由——route 6.网络连接状态——ss 或 net…

【Java并发】聊聊concurrentHashMap的put核心流程

结构介绍 1.8中concurrentHashMap采用数组链表红黑树的方式存储&#xff0c;并且采用CASSYN的方式。在1.7中主要采用的是数组链表&#xff0c;segment分段锁reentrantlock。本篇主要在1.8基础上介绍下. 那么&#xff0c;我们的主要重点是分析什么呢&#xff0c;其实主要就是p…

从0开始的编程生活

1.自我介绍 CSDN的小伙伴们&#xff0c;大家好&#xff0c;我是一名来自双非二本院校的大二学生&#xff0c;学编程有一段时间了&#xff0c;这篇博客呢&#xff0c;不是讲与技术相关的内容&#xff0c;而是对自己的阶段性总结和对未来的规划 2.目标 高中的目标很简单也很统一…

RabbitMQ笔记

RabbitMQ 安装MQ docker run \-e RABBITMQ_DEFAULT_USERitheima \-e RABBITMQ_DEFAULT_PASS123321 \-v mq-plugins:/plugins \--name mq \--hostname mq \-p 15672:15672 \-p 5672:5672 \--network hmall \-d \rabbitmq:3.8-management可以看到在安装命令中有两个映射的端口&…

线程与UI操作

子线程中不能执行UI操作。 UI 操作指的是与用户界面&#xff08;User Interface&#xff09;相关的操作&#xff0c;包括但不限于以下几种&#xff1a; 更新视图&#xff1a;例如更改 TextView 的文本内容、设置 ImageView 的图片等。处理用户输入&#xff1a;例如响应按钮点…

银联扫码第三方支付接口申请:开启便捷支付新时代

随着移动支付的普及&#xff0c;越来越多的商家开始接受微信、支付宝等第三方支付平台的付款方式。然而&#xff0c;作为国内最大的银行卡组织&#xff0c;银联也在不断拓展其业务范围&#xff0c;推出了自己的扫码支付接口。本文将为您详细介绍银联扫码第三方支付接口的申请流…

GO语言笔记3-指针

指针的概念 先看一段代码的输出 package main import "fmt" func main(){ var age int 18fmt.Println("age的内存地址值是:",&age)//age的内存地址值是: 0xc000012090// 定义一个指针变量// *int 是一个指针类型&#xff0c;可以理解为指向int类型的…

Python数据分析:入门到实践

一、引言 &#xff08;用手机写的&#xff0c;明天重新排版。&#xff09; 在当今数据驱动的时代&#xff0c;数据分析已经成为各行各业不可或缺的一部分。Python作为一种高效、易学的编程语言&#xff0c;在数据分析领域具有广泛的应用。本文将带你从Python数据分析的入门知…

两个视频怎么合并成一个视频?教你合并视频

两个视频怎么合并成一个视频&#xff1f;如果你是一名视频爱好者&#xff0c;或者是一名自媒体创作者&#xff0c;那么你一定遇到过需要将两个视频合并为一个的情况。有时候&#xff0c;你可能需要将一个长视频切割成多个片段&#xff0c;或者将多个视频片段合并成一个完整的视…

Spring MVC的RequestMapping注解、controller方法返回值

1.使用说明 作用&#xff1a;用于建立请求URL和处理请求方法之间的对应关系。 出现位置&#xff1a; 类上&#xff1a; 请求 URL的第一级访问目录。此处不写的话&#xff0c;就相当于应用的根目录。写的话需要以/开头。它出现的目的是为了使我们的 URL 可以按照模块化管理&…

我的1827创作纪念日

机缘 习惯性早上打开电脑&#xff0c;看看CSDN上的资讯&#xff0c;了解行业动态、当前新的技术和大佬的分享。自己动手写应该是2019 年 01 月 08 日&#xff0c;当时应该是在用安装和使用Oracle&#xff0c;遇到一些问题&#xff0c;写下第一篇博客 Oracle存储过程常见问题及…

一、Mybatis 简介

本章概要 简介持久层框架对比快速入门&#xff08;基于Mybatis3方式&#xff09; 1.1 简介 https://mybatis.org/mybatis-3/zh/index.html MyBatis最初是Apache的一个开源项目iBatis, 2010年6月这个项目由Apache Software Foundation迁移到了Google Code。随着开发团队转投G…

2024.1.9 Spark SQL day06 homework

目录 一. Spark SQL中数据清洗的API有哪些&#xff0c;各自作用是什么&#xff1f; 二. 设置Spark SQL的shuffle分区数的方式有哪几种 三. 数据写出到数据库需要注意什么? 四. Spark程序运行集群分类 一. Spark SQL中数据清洗的API有哪些&#xff0c;各自作用是什么&#x…

【解决方案】 无法将“pip“项识别为 cmdlet、函数、脚本文件

在当今的软件开发和运维领域&#xff0c;Python已经成为了一个不可或缺的工具。而pip&#xff0c;作为Python的包管理工具&#xff0c;更是Python生态系统中不可或缺的一部分。然而&#xff0c;有时候我们可能会遇到一个令人困扰的问题&#xff1a;无法将“pip”项识别为cmdlet…

zookeeper 与eureka区别

CAP定理 在分布式系统的发展中&#xff0c;影响最大的莫过于CAP定理了&#xff0c;是分布式系统发展的理论基石。 2000年&#xff0c;加州大学的计算机科学家 Eric Brewer提出了CAP猜想 2002 年&#xff0c;麻省理工学院的 Seth Gilbert 和 Nancy Lynch 从理论上证明了 CAP 猜…

c++实现支持动态扩容的栈(stack)

1.在栈容量满时自动扩容: 支持自动扩容栈实现: // // myStack.hpp // algo_demo // // Created by Hacker X on 2024/1/9. //#ifndef myStack_hpp #define myStack_hpp #include <stdio.h> #include <string.h> //栈实现 //1.入栈 //2.出栈 //3.空栈 //4.满栈 …

栈的模拟实现

栈的模拟实现 一:什么是栈二:IStack 接口三:MyStack类:1:push(int x):2:pop()3:peek()4:size(),empty(),full() 三:四:栈的时间复杂度: 一:什么是栈 栈是以先进后出(后进先出)的形式来组织数据结构 比如: 先装入的子弹后射出,后装入的子弹先射出,这就是一种典型的栈. 二:ISta…