五种IO模型与非阻塞IO

ops/2024/9/22 20:21:59/

        通常我们进行网络通信其实就是以网络为介质的进程间通信,进程间通信的本质就是 IO(input、output),从进程间的角度出发,IO 是数据的传输和交换,但是站在内存的角度出发,IO 其实的内存和外设之间数据拷贝

        平时我们在使用 read/recv 系统调用接口读取数据的时候,是先从接收缓冲区中读出数据,讲数据读完之后,若还想读,那么就会阻塞,在这个阻塞等待的过程中本质就是在等待数据被发送到接收缓冲区,缓冲区有数据之后进行 IO 就可以读出数据;使用 write/send 系统调用接口发送数据同理,当发送缓冲区满的时候就会阻塞等待,不满的时候就通过 IO 将数据拷贝到发送缓存区。所以对于我们的 IO 操作本质就是等待加上拷贝(IO = 等待 + 拷贝)

        本篇还会介绍非阻塞 IO 的相关接口和代码。

目录

IO%E6%A8%A1%E5%9E%8B-toc" style="margin-left:80px;">五种IO模型

IO-toc" style="margin-left:80px;">非阻塞IO

IO%E6%A8%A1%E5%9E%8B">五种IO模型

        在 IO 过程中,往往拷贝的时间是非常迅速的,然而等待却不知道需要等待多久,所以当我们要设计出高效的 IO 过程时,就需要将减少 IO 等待的时间(比如并行等待多个 IO 过程,同一时段分担多个 IO 等待的时间)。对于 IO 操作而言一共存在 5 中 IO 模型,如下:

        阻塞 IO:在内核中将数据准备好之前,系统会一直等待所有的套接字,知道数据来临才进行拷贝。(阻塞 IO 是最常见的 IO 模型)

        非阻塞 IO:若内核还没有将数据准备好,系统调用会直接返回,只有当数据准备好系统调用才会直接读写数据(其实就是在等待数据准备的时候,系统会去做其他的事情)。

        信号驱动 IO:内核将数据准备好的时候,会使用 SIGIO 信号通知应用进程进行 IO 操作。

        IO 多路转接:虽然从流程图上看起来和阻塞 IO 类似,实际上最核心在于 IO 多路转接能够同时等待多个文件描述符的就绪状态(相当于同时等待多个 IO 操作,哪一个数据准备好了就对哪个进行 IO 操作,对于多路转接 IO,这篇 blog 从代码层面实现了多路转接 IOXXXXXXXXXX)。

        异步 IO:由内核在数据拷贝完成时,通知应用程序(相当于 IO 操作和自己的任务已经完全分离,既可以做应用自己的任务,又可以做 IO

        对于以上的 IO 操作,效率最高的是多路转接 IO,因为可以同时等待多个数据准备,也就是在同一时间内多路转接等待数据准备的次数更多,自然数据准备的效果更好。

        以上第五种 IO 模式为异步 IO,其余四种 IO 模式为同步 IO,对于同步 IO 和异步 IO 的界定方式就是发起 IO 的应用进程是否亲自参与到 IO 的过程中,其他四种方式的 IO,应用进程都参与到了 IO 过程中。

        阻塞和非阻塞:阻塞调用是指调用结果返回之前,当前线程会被挂起,调用线程只有在得到结果之后才会返回。非阻塞:不能立刻得到结果之前,该调用不会阻塞当前线程。

IO">非阻塞IO

        当我们想要进行非阻塞 IO 的时候,我们可以使用系统调用 fcntl 来对我们的文件描述符进行设定,将其设定为非阻塞读写的文件描述符,使用方法如下:

#include <unistd.h>
#include <fcntl.h>int fcntl(int fd, int cmd, ... /* arg */ );传入的 cmd 的值不同,后面追加的参数也不相同fcntl 函数共有五种功能:
复制一共现有的描述符(cmd=F_DUPFD)
获得/设置文件描述符标记(cmd=F_GETFD/F_SETFD)
获得/设置文件状态标记(cmd=F_GETFL/F_SETFL)
获得/设置异步IO所有权(cmd=F_GETOWN/F_SETOWN)
获得/设置记录锁(cmd=F_GETLK,F_SETLK/F_SETLKW)

        我们将使用如上接口写一个非阻塞 IO 的代码,如下:

        Main.cc:

#include <iostream>
#include <unistd.h>
#include "Common.hpp"int main() {// 将对应的文件描述符设置为非阻塞SetNonBlock(0);char buff[1024];while (true) {// 从键盘读取ssize_t n = read(0, buff, sizeof(buff) - 1);if (n > 0) {buff[n] = 0;std::cout << "echo > " << buff << std::endl;} else if (n == 0) {std::cout << "read done" << std::endl;break;} else {// 当非阻塞读取数据的时候,若没有读到数据返回值小于0if (errno == EWOULDBLOCK) {// 错误码等于EWOULDBLOCK的时候表面底层没有数据,需要轮询读取sleep(1);std::cout << "havn't data, begin to rotate" << std::endl;continue;} else if (errno == EINTR) {// 数据因为被发送的信号而打断接收,重新读取continue;} else {std::cout << "read error" << std::endl;break;}}}return 0;
}

        Common.cc:

#pragma once
#include <iostream>
#include <fcntl.h>
#include <unistd.h>void SetNonBlock(int fd) {// 使用F_GETFL将当前文件描述符的属性取出来(f1当前可以将其看作为位图)int f1 = fcntl(fd, F_GETFL);if (f1 < 0) {std::cout << "SetNonBLock Fail" << std::endl;return;}// 然后使用F_SETFL将文件描述符设置回去,设置回去的同时,加上一个O_NONBLOCK参数fcntl(fd, F_SETFL, f1 | O_NONBLOCK);
}

        makefile:

testNonBlock:Main.ccg++ -o $@ $^ -std=c++11
.PHONY:clean
clean:rm -f testNonBlock

        测试结果如下:

         通常情况下使用的非阻塞 IO 的情况还是较少,因为非阻塞 IO 的轮询会花费较多的 CPU 资源,所以只有在很少的情况下才会使用非阻塞 IO


http://www.ppmy.cn/ops/112644.html

相关文章

网络原理(3)—— 应用层、传输层(TCP)

1. 应用层 日常开发中最常用到的一层&#xff0c;主要涉及到两种情况&#xff1a; 1) 使用现成的应用层协议 2) 自己定义应用层协议 1.1 自定义应用层协议的流程 1. 明确前后端交互过程中需要传递哪些信息 实例&#xff1a;开发一个外卖软件 打开软件&#xff0c;首先需要展…

【系统架构设计师】特定领域软件架构(经典习题)

更多内容请见: 备考系统架构设计师-核心总结索引 文章目录 【第1~2题】【第3~4题】【第5~6题】【第7~8题】【第9~10题】【第11~12题】【第13~14题】【第15~17题】【试题一(共25分)】【问题 1】(13 分)【第1~2题】 特定领域软件架构(Domain Specific Software Architecture…

二十种编程语言庆祝中秋节

二十种编程语言庆祝中秋节 文章目录 二十种编程语言庆祝中秋节中秋快乐&#xff01;家人们 &#x1f973;一 Python二 C三 C四 Java五 C#六 Perl七 Go八 Asp九 PHP十 JavaScript十一 JavaScript HTML十二 Visual Basic十三 早期 VB十四 Visual C十五 Delphi十六 Shell十七 Cobo…

使用ESP8266和OLED屏幕实现一个小型电脑性能监控

前言 最近大扫除&#xff0c;发现自己还有几个ESP8266MCU和一个0.96寸的oled小屏幕。又想起最近一直想要买一个屏幕作为性能监控&#xff0c;随机开始自己diy。 硬件&#xff1a; ESP8266 MUColed小屏幕杜邦线可以传输数据的数据线 环境 Windows系统Qt6Arduino Arduino 库…

电学基础概念详解及三相电公式汇总

​​​​​​​ 本文全面介绍了电路的基本组成、电学核心概念以及三相电的常用公式。首先&#xff0c;通过水力学中的现象类比&#xff0c;生动解释了电路中电池、开关、电阻和灯泡等元素的功能&#xff0c;帮助读者更好地理解电压、电流和电阻之间的关系。随后&#xff0c;详…

使用Python实现深度学习模型:智能家电控制与优化

随着物联网(IoT)和人工智能(AI)技术的快速发展,智能家电控制与优化成为了现代家庭生活的重要组成部分。通过深度学习技术,我们可以实现对家电设备的智能控制和优化,提高能源效率和用户体验。本文将详细介绍如何使用Python实现一个简单的深度学习模型,用于智能家电控制与…

2024重生之回溯数据结构与算法系列学习【无论是王道考研人还真爱粉都能包会的;不然别给我家鸽鸽丢脸好嘛?】

目录 数据结构王道第2章之顺序表 顺序表的定义和基本操作 定义&#xff1a; 基本操作&#xff1a; 基本操作&#xff1a; ​编辑 顺序表的实现-静态分配​编辑 顺序表的静态分配初始化 如果“数组”存满了怎么办&#xff1a; 顺序表的实现-动态分配&#xff1a; ​编辑 顺序表…

【App】React Native

React Native 的优势&#xff1a; 开发体验好 用统一的代码规范开发移动端程序&#xff0c;不用关注移动端的差异.开发成本低 开发一次&#xff0c;可以生成 Android 和 IOS 俩个系统上的 App学习成本低 只要掌握 JavaScript 和 React 就可以进行移动端开发 React Native 的不…