Linux 5种网络IO模型

Linux IO模型

网络IO的本质是socket的读取,socket在linux系统被抽象为流,IO可以理解为对流的操作。刚才说了,对于一次IO访问(以read举例),数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间。所以说,当一个read操作发生时,它会经历两个阶段:

  1. 第一阶段:等待数据准备 (Waiting for the data to be ready)。

  2. 第二阶段:将数据从内核拷贝到进程中 (Copying the data from the kernel to the process)。

对于socket流而言,

  1. 第一步:通常涉及等待网络上的数据分组到达,然后被复制到内核的某个缓冲区。

  2. 第二步:把数据从内核缓冲区复制到应用进程缓冲区。

1、阻塞IO模型 

在 linux 中,默认情况下所有的 socket 都是阻塞的。

对于socket流而言,

  1. 第一步:通常涉及等待网络上的数据分组到达,然后被复制到内核的某个缓冲区。

  2. 第二步:把数据从内核缓冲区复制到应用进程缓冲区。

当用户进程调用了 read 这个系统调用, kernel 就开始了 IO 的第一个阶段:准备数据。对于network io 来说,很多时候数据在一开始还没有到达(比如,还没有收到一个完整的数据包),这个时候 kernel 就要等待足够的数据到来。而在用户进程这边,整个进程会被阻塞。当 kernel一直等到数据准备好了,它就会将数据从 kernel 中拷贝到用户内存,然后 kernel 返回结果,用户进程才解除 block 的状态,重新运行起来。

所谓阻塞型接口是指系统调用(一般是 IO 接口)不返回调用结果并让当前线程一直阻塞,只有当该系统调用获得结果或者超时出错时才返回。实际上,除非特别指定,几乎所有的 IO 接口 ( 包括 socket 接口 ) 都是阻塞型的。这这就带来了一个很大的问题,如在调用 send()的同时,线程将被阻塞,在此期间,线程将无法执行任何运算或响应任何的网络请求,一个简单的改进方案是在服务器端使用多线程(或多进程)

2、非阻塞IO模型 

Linux 下,可以通过设置 socket 使其变为 non-blocking。当对一个 non-blocking socket 执行读操作时,流程是这个样子:

 

同步非阻塞就是 “每隔一会儿瞄一眼进度条” 的轮询(polling)方式。在这种模型中,设备是以非阻塞的形式打开的。这意味着 IO 操作不会立即完成,read 操作可能会返回一个错误代码,说明这个命令不能立即满足(EAGAIN 或 EWOULDBLOCK)。

在网络IO时候,非阻塞IO也会进行recvform系统调用,检查数据是否准备好,与阻塞IO不一样,"非阻塞将大的整片时间的阻塞分成N多的小的阻塞, 所以进程不断地有机会 '被' CPU光顾"。

也就是说非阻塞的recvform系统调用调用之后,进程并没有被阻塞,内核马上返回给进程,如果数据还没准备好,此时会返回一个error。进程在返回之后,可以干点别的事情,然后再发起recvform系统调用。重复上面的过程,循环往复的进行recvform系统调用。这个过程通常被称之为轮询。轮询检查内核数据,直到数据准备好,再拷贝数据到进程,进行数据处理。需要注意,拷贝数据整个过程,进程仍然是属于阻塞的状态

3、多路复用IO模型 

解决服务器对多个连接套接字的读取的关键:

1、是需将可读判断与实际读取数据相分离。

2、是能同时支持多个套接字可读判断。

因此我们需要一种能够预先告知内核的能力,使得内核一旦发现进程指定的一个或多个I/O条件就绪,即输入已经准备好被读取,它就通知进程。这个行为称之为I/O复用。在Linux平台上,提供了select、poll和epoll这几种系统调用作为I/O复用的方式。

select/epoll的好处就在于单个线程就可以同时处理多个网络连接的IO。它的基本原理就是select,poll,epoll这个function会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程。

当用户进程调用了select,那么整个进程会被block,而同时,kernel会“监视”所有select负责的socket,当任何一个socket中的数据准备好了,select就会返回。这个时候用户进程再调用read操作,将数据从kernel拷贝到用户进程。

其中的任意一个描述符进入读就绪状态,select, poll,epoll函数就可以返回。对于监视的方式,又可以分为 select, poll, epoll三种方式。

如果处理的连接数不是很高的话,使用select/epoll的web server不一定比使用multi-threading + blocking IO的web server性能更好,可能延迟还更大。(select/epoll的优势并不是对于单个连接能处理得更快,而是在于能处理更多的连接。)

IO多路复用是阻塞在select,epoll这样的系统调用之上,而没有阻塞在真正的I/O系统调用如recvfrom之上。

在I/O编程过程中,当需要同时处理多个客户端接入请求时,可以利用多线程或者I/O多路复用技术进行处理。I/O多路复用技术通过把多个I/O的阻塞复用到同一个select的阻塞上,从而使得系统在单线程的情况下可以同时处理多个客户端请求。

select、poll、epoll 区别总结:

1、支持一个进程所能打开的最大连接数

select:单个进程所能打开的最大连接数有FD_SETSIZE宏定义,其大小是32个整数的大小(在32位的机器上,大小就是3232,同理64位机器上FD_SETSIZE为3264),当然我们可以对进行修改,然后重新编译内核,但是性能可能会受到影响,这需要进一步的测试。

poll:poll本质上和select没有区别,但是它没有最大连接数的限制,原因是它是基于链表来存储的。

epoll:虽然连接数有上限,但是很大,1G内存的机器上可以打开10万左右的连接,2G内存的机器可以打开20万左右的连接。

2、fd剧增后带来的IO效率问题

select:因为每次调用时都会对连接进行线性遍历,所以随着FD的增加会造成遍历速度慢的“线性下降性能问题”。

poll:同上

epoll:因为epoll内核中实现是根据每个fd上的callback函数来实现的,只有活跃的socket才会主动调用callback,所以在活跃socket较少的情况下,使用epoll没有前面两者的线性下降的性能问题,但是所有socket都很活跃的情况下,可能会有性能问题。

3、 消息传递方式

select:内核需要将消息传递到用户空间,都需要内核拷贝动作

poll:同上

epoll:epoll通过内核和用户空间共享一块内存来实现的。
 

优点:

与传统的多线程/多进程模型比,I/O多路复用的最大优势是系统开销小,系统不需要创建新的额外进程或者线程,也不需要维护这些进程和线程的运行,降底了系统的维护工作量,节省了系统资源,I/O多路复用的主要应用场景如下:

1、服务器需要同时处理多个处于监听状态或者多个连接状态的套接字。

2、服务器需要同时处理多种网络协议的套接字。

同步模型:

了解了前面三种IO模式,在用户进程进行系统调用的时候,他们在等待数据到来的时候,处理的方式不一样,直接等待,轮询,select或poll轮询。从整个IO过程来看,他们都是顺序执行的,因此可以归为同步模型(synchronous)。都是进程主动等待且向内核检查状态。

高并发的程序一般使用同步非阻塞方式而非多线程 + 同步阻塞方式。要理解这一点,首先要扯到并发和并行的区别。比如去某部门办事需要依次去几个窗口,办事大厅里的人数就是并发数,而窗口个数就是并行数。也就是说并发数是指同时进行的任务数(如同时服务的 HTTP 请求),而并行数是可以同时工作的物理资源数量(如 CPU 核数)。通过合理调度任务的不同阶段,并发数可以远远大于并行度,这就是区区几个 CPU 可以支持上万个用户并发请求的奥秘。

注意:关于IO多路复用是同步阻塞模型还是异步阻塞模型?在此给大家分析下:

同步是需要主动等待消息通知,而 异步则是被动接收消息通知,通过回调、通知、状态等方式来被动获取消息。IO多路复用在阻塞到select阶段时,用户进程是主动等待并调用select函数获取数据就绪状态消息,并且其进程状态为阻塞。所以,把IO多路复用归为同步阻塞模式。

4、信号驱动IO模型 

首先我们允许Socket进行信号驱动IO,并安装一个信号处理函数,进程继续运行并不阻塞。当数据准备好时,进程会收到一个SIGIO信号,可以在信号处理函数中调用I/O操作函数处理数据。

5、异步IO模型 

相对于同步IO,异步IO不是顺序执行。用户进程进行aio_read系统调用之后,无论内核数据是否准备好,都会直接返回给用户进程,然后用户态进程可以去做别的事情。等到socket数据准备好了,内核直接复制数据给进程,然后从内核向进程发送通知IO两个阶段,进程都是非阻塞的

Linux提供了AIO库函数实现异步,但是用的很少。目前有很多开源的异步IO库,例如libevent、libev、libuv。异步过程如下图所示:

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

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

相关文章

LL库实现SPI MDA发送方式驱动WS2812

1,首先打卡STM32CubeMX,配置一下工程,这里使用的芯片是STM32F030F4P6。 时钟 SPI外设 SPI DMA 下载接口,这个不配置待会下程序后第二次就不好下载调试了。 工程配置,没啥说的 选择生成所有文件 将驱动都改为LL库 然后直…

jmeter errstr :“unsupported field type for multipart.FileHeader“

在使用jmeter测试接口的时候,提示errstr :"unsupported field type for multipart.FileHeader"如图所示 这是因为我们 在HTTP信息头管理加content-type参数有问题 直接在HTTP请求中,勾选: use multipart/form-data for POST【中文…

22、touchGFX学习Model-View-Presenter设计模式

touchGFX采用MVP架构,如下所示: 本文界面如下所示: 本文将实现两个操作: 1、触摸屏点击开关按键实现打印开关显示信息,模拟开关灯效果 2、板载案按键控制触摸屏LED灯的显示和隐藏 一、触摸屏点击开关按键实现打印开…

docker搭建LNMP

docker安装 略 下载镜像 nginx:最新版php-fpm:根据自己需求而定mysql:根据自己需求定 以下是我搭建LNMP使用的镜像版本 rootVM-12-16-ubuntu:/docker/lnmp/php/etc# docker images REPOSITORY TAG IMAGE ID CREATED SIZE mysql 8.0…

Linux的基本权限(文件,目录)

文章目录 前言一、Linux权限的概念二、Linux权限管理 1.文件访问者分类2.文件类型和访问类型3.文件访问权限的相关设置方法三、目录的权限四、权限的总结 前言 Linux下一切皆文件,指令的本质就是可执行文件,直接安装到了系统的某种路径下 一、Linux权限的…

SpringCloud实用篇6——elasticsearch搜索功能

目录 1 DSL查询文档1.1 DSL查询分类1.2 全文检索查询1.2.1 使用场景1.2.2 基本语法1.2.3 示例1.2.4 总结 1.3 精准查询1.3.1 term查询1.3.2 range查询1.3.3 总结 1.4.地理坐标查询1.4.1 矩形范围查询1.4.2 附近查询 1.5 复合查询1.5.1 相关性算分1.5.2 算分函数查询1&#xff0…

【大数据Hive】hive 事务表使用详解

目录 一、前言 二、Hive事务背景知识 hive事务实现原理 hive事务原理之 —— delta文件夹命名格式 _orc_acid_version 说明 bucket_00000 合并器(Compactor) 二、Hive事务使用限制 参数设置 客户端参数设置 客户端参数设置 三、Hive事务使用操作演示 操作步骤 客…

【C语言】回调函数,qsort排序函数的使用和自己实现,超详解

文章目录 前言一、回调函数是什么二、回调函数的使用1.使用标准库中的qsort函数2.利用qsort函数对结构体数组进行排序 三、实现qsort函数总结 先记录一下访问量突破2000啦,谢谢大家支持!!! 这里是上期指针进阶链接,方便…

【100天精通python】Day37:GUI界面编程_PyQT从入门到实战(上)

目录 专栏导读 1 PyQt6 简介: 1.1 安装 PyQt6 和相关工具: 1.2 PyQt6 基础知识: 1.2.1 Qt 的基本概念和组件: 1.2.2 创建和使用 Qt 窗口、标签、按钮等基本组件 1.2.3 布局管理器:垂直布局、水平布局、网格布局…

mysql与redis区别

mysql和redis的数据库类型 mysql是关系型数据库,主要用于存放持久化数据,将数据存储在硬盘中,读取速度较慢。 redis是NOSQL,即非关系型数据库,也是缓存数据库,即将数据存储在缓存中,缓存的读取速…

网络

mcq Java 传输层:拆分和组装,完成端到端的消息传递,流量控制,差错控制等 网络层: 寻址、路由,复用,拥塞控制,完成源到宿的传递。 显然A选项是错误的,有流量控制的是传输层…

netty学习分享(一)

TCP与UDP TCP 是面向连接的、可靠的流协议,通过三次握手建立连接,通讯完成时要拆除连接。 UDP是面向无连接的通讯协议,UDP通讯时不需要接收方确认,属于不可靠的传输,可能会出现丢包现象 端口号: 端口号用…

【uniapp】uniapp设置安全区域:

文章目录 一、效果图:二、实现代码: 一、效果图: 二、实现代码: {"path": "pages/index/index","style": {"navigationStyle": "custom","navigationBarTextStyle": "white","navigationBarTitle…

Matlab工具NIFTI包的基本功能函数

Matlab工具NIFTI包的基本功能函数 Nifti 格式最初是为神经影像学发明的。神经影像信息学技术计划(NIFTI)将 NIfTI 格式预设为 ANALYZE7.5 格式的替代品。它最初的应用领域是神经影像,但是也被用在其他领域。这种格式的主要特点就是它包含两个…

Docker基础入门:常规软件安装与镜像加载原理

Docker基础入门:常规软件安装与镜像加载原理 一、Docker常规软件安装1.1、部署nginx1.2、部署tomcat1.3、部署elasticsearch1.4、如何部署kibana-->连接elasticsearch1.5、部署可视化工具 二、 镜像加载原理2.1、镜像是什么2.2、Docker镜像加速原理2.3、分层理解…

Grafana Prometheus 通过JMX监控kafka 【2023最新方式】

第三方kafka exporter方案 目前网上关于使用Prometheus 监控kafka的大部分资料都是使用一个第三方的 kafka exporter,他的原理大概就是启动一个kafka客户端,获取kafka服务器的信息,然后提供一些metric接口供Prometheus使用,随意它…

07_Hudi案例实战、Flink CDC 实时数据采集、Presto、FineBI 报表可视化等

7.第七章 Hudi案例实战 7.1 案例架构 7.2 业务数据 7.2.1 客户信息表 7.2.2 客户意向表 7.2.3 客户线索表 7.2.4 线索申诉表 7.2.5 客户访问咨询记录表 7.3 Flink CDC 实时数据采集 7.3.1 开启MySQL binlog 7.3.2 环境准备 7.3.3 实时采集数据 7.3.3.1 客户信息表 7.3.3.2 客户…

ubuntu安装jdk、emqx、nginx

一、安装jdk 要在Ubuntu上安装JDK 1.8,您可以按照以下步骤进行操作: 打开终端(CtrlAltT)。确保您的系统已更新: sudo apt update sudo apt upgrade安装OpenJDK 8: sudo apt install openjdk-8-jdk安装完成…

.net core发布到IIS上出现 HTTP 错误 500.19

1.检查.net core 环境运行环境是否安装完成,类似如下环境 2.IIS是否安装全 本次原因就是IIS未安装全导致的 按照网上说的手动重启iis(iisreset)也不行

基于C#的消息处理的应用程序 - 开源研究系列文章

今天讲讲基于C#里的基于消息处理的应用程序的一个例子。 我们知道,Windows操作系统的程序是基于消息处理的。也就是说,程序接收到消息代码定义,然后根据消息代码定义去处理对应的操作。前面有一个博文例子( C#程序的启动显示方案(无窗口进程发…