Linux高级IO
1. 五种IO模型
IO是什么?
IO是计算机领域中的缩写,指的是输入/输出(Input/Output)。在计算机系统中,IO通常指的是计算机与外部设备(如键盘、鼠标、显示器、硬盘、网络等)之间的数据交换过程。
输入(Input) 输入指的是数据从外部设备传输到计算机系统内部的过程。例如:从键盘输入文字或命令到计算机中;从网络接收数据包;从磁盘读取文件内容。
输出(Output) 输出指的是数据从计算机系统传输到外部设备的过程。例如:将计算机处理后的数据显示在屏幕上;将数据写入到打印机以打印文档;将文件保存到硬盘上。
数据是怎么从输入到输出的呢,过程是什么样的?
简单的看,调用read和write函数将数据传入OS,由OS传给不同的外设。
输入和输出(IO)的过程发生在计算机系统与外部环境之间的数据交换过程中。在计算机系统内部,IO的过程涉及多个层次和组件:
应用层:应用程序通过调用操作系统提供的IO接口(如read和write函数)来实现数据的输入和输出。
操作系统:操作系统负责管理和调度IO操作,包括与设备驱动程序的交互、数据缓存、IO调度等。
设备驱动程序:设备驱动程序是操作系统和硬件设备之间的接口,负责控制和管理具体的硬件设备,处理来自设备的IO请求和响应。
总结来说,IO过程涉及了从用户层到操作系统内核的数据传输,以及操作系统到物理设备或网络的数据传输过程。
操作系统怎么判断IO发生,或者说是输入输出发生?
通常在系统调用,硬件中断,状态改变,网络活动,资源占用这些情况下会产生IO事件。
在计算机系统中,IO操作通常可以分解为两个主要阶段:等待(或者说请求)和拷贝(或传输)。在理解拷贝条件是否发生之前,需要考虑以下几个关键点:
判断等待(或请求)条件发生:
IO请求发起:应用程序发出IO请求,例如读取文件内容、发送网络数据等。
系统调用:操作系统接收到应用程序的IO请求,然后开始进行IO操作的准备工作,这通常包括分配内核缓冲区、准备硬件接口等。
判断拷贝(或传输)条件发生:
系统调用返回:当应用程序发出读取或写入请求后,操作系统会开始处理这个请求,并最终完成数据的拷贝操作。可以通过系统调用的返回状态来判断拷贝操作是否已经完成。
数据可用性:在读取操作中,可以通过检查读取的数据是否已经在应用程序的缓冲区中可用来判断拷贝操作是否完成。类似地,在写入操作中,可以通过检查数据是否成功地传输到目标设备或目标位置来确认拷贝操作的完成。
事件通知:有些IO操作在完成后会通过事件通知机制来通知应用程序,例如异步IO模型中的完成事件或回调。应用程序可以通过这些事件或回调来确认拷贝操作已经完成。
所以为了提高数据交互的效率,我们要提高IO操作的效率。
总结来说:
1. IO就是Input和Output,是计算机与外部进行交换的过程。
2. 为了实现应用层的数据交换,我们通常使用read和write函数,本质上就是把数据从用户层写给操作系统,再本质上就是拷贝函数。
3. IO = 等 + 拷贝 ,再进行拷贝之前,我们要判断拷贝条件是否发生。
4. 所以我们想要实现高效的IO,在单位的时间里,等 或 拷贝 的时间越小效率越高,但是一般拷贝的时间差不多,所以怎么降低 等 的比重,就是我们提高IO效率的办法。
所以说下面的可以提高IO效率的模型,都是降低了等待的时间。
怎么降低等待的时间呢?
我们先以简单的钓鱼例子来概括一下这五种IO模型:
阻塞IO模型:你投放鱼饵后,就等待鱼儿咬钩。在等待鱼咬钩的过程中,不能做其他事情,只能一直盯着浮标,直到有鱼上钩。
非阻塞IO模型:你在每次投放鱼饵后,你不会傻等鱼儿上钩,而是不断定期检查浮标的状态。如果没有鱼上钩,就继续做其他事情,直到鱼上钩就收杆。
IO复用模型:你可能会使用多根钓竿,使用10个鱼竿,100个鱼竿,可以是无穷的鱼竿,当有任何一根钓竿的浮标动了,你就知道有鱼上钩,然后去收杆。
信号驱动IO模型:你可能会使用自动报警装置。每次投放鱼饵后,设定了一个报警器,当有鱼上钩时触发报警器发出信号。在听到报警器响时,立即去收杆。
异步IO模型:你会雇佣一个专业的钓鱼服务公司。他们会使用不同的钓鱼方式,但是你完全不用关心,你只要他们通知你来收杆就可以了。
1.1 阻塞IO
阻塞IO: 在内核将数据准备好之前, 系统调用会一直等待. 所有的套接字, 默认都是阻塞方式。
阻塞IO是最常见的IO模型。
我们写一个简单的套接字阻塞IO:
Socket.hpp
#include <iostream>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
class Sock
{
public:
Sock()
{
}
~Sock()
{
}
//创建socket
void Socket()
{
//表示创建一个IPV4,协议为tcp的套接字,0表示使用默认协议,
_sockfd=socket(AF_INET,SOCK_STREAM,0);
if(_sockfd){
perror("Socket creation failed");
return ;
}
}
//绑定端口
void Bind