缓存 IO 的缺点:
数据在传输过程中需要在应用程序地址空间和内核进行多次数据拷贝操作,这些数据拷贝操作所带来的 CPU 以及内存开销是非常大的 。
二、IO模型网络IO的本质是socket的读取,socket在linux系统被抽象为流,IO可以理解为对流的操作 。刚才说了,对于一次IO访问(以read举例),数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间 。
所以说,当一个read操作发生时,它会经历两个阶段:
第一阶段:等待数据准备 (Waiting for the data to be ready) 。
第二阶段:将数据从内核拷贝到进程中 (Copying the data from the kernel to the process) 。
对于socket流而言,
第一步:通常涉及等待网络上的数据分组到达,然后被复制到内核的某个缓冲区 。
第二步:把数据从内核缓冲区复制到应用进程缓冲区 。
网络应用需要处理的无非就是两大类问题,网络IO,数据计算 。相对于后者,网络IO的延迟,给应用带来的性能瓶颈大于后者 。
网络IO的模型大致有如下几种:
· 同步模型(synchronous IO)
· 阻塞IO(bloking IO)
· 非阻塞IO(non-blocking IO)
· 多路复用IO(multiplexing IO)
· 信号驱动式IO(signal-driven IO)
· 异步IO(asynchronous IO)注:由于signal driven IO在实际中并不常用,所以我这只提及剩下的四种IO Model 。
1、堵塞IO模型应用程序调用一个 IO 函数,导致应用程序阻塞,等待数据准备好 。如果数据没有准备好,一直等待…数据准备好了,从内核拷贝到用户空间,IO 函数返回成功指示 。
当调用 recv()函数时,系统首先查是否有准备好的数据 。如果数据没有准备好,那么系统就处于等待状态 。当数据准备好后,将数据从系统缓冲区复制到用户空间,然后该函数返回 。在套接应用程序中,当调用 recv()函数时,未必用户空间就已经存在数据,那么此时 recv()函数就会处于等待状态 。
文章插图
2、非堵塞IO模型
文章插图
我们把一个 SOCKET 接口设置为非阻塞就是告诉内核,当所请求的 I/O 操作无法完成时,不要将进程睡眠,而是返回一个错误 。这样我们的 I/O 操作函数将不断的测试数据是否已经准备好,如果没有准备好,继续测试,直到数据准备好为止 。在这个不断测试的过程中,会大量的占用 CPU 的时间 。上述模型绝不被推荐 。
3、IO 复用模型
文章插图
由于同步非阻塞方式需要不断主动轮询,轮询占据了很大一部分过程,轮询会消耗大量的CPU时间,而 “后台” 可能有多个任务在同时进行,人们就想到了循环查询多个任务的完成状态,只要有任何一个任务完成,就去处理它 。如果轮询不是进程的用户态,而是有人帮忙就好了 。那么这就是所谓的 “IO 多路复用”
IO多路复用有两个特别的系统调用select、poll、epoll函数 。select调用是内核级别的,select轮询相对非阻塞的轮询的区别在于---前者可以等待多个socket,能实现同时对多个IO端口进行监听,当其中任何一个socket的数据准好了,就能返回进行可读,然后进程再进行recvform系统调用,将数据由内核拷贝到用户进程,当然这个过程是阻塞的 。select或poll调用之后,会阻塞进程,与blocking IO阻塞不同在于,此时的select不是等到socket数据全部到达再处理, 而是有了一部分数据就会调用用户进程来处理 。如何知道有一部分数据到达了呢?监视的事情交给了内核,内核负责数据到达的处理 。也可以理解为"非阻塞"吧 。
I/O复用模型会用到select、poll、epoll函数,这几个函数也会使进程阻塞,但是和阻塞I/O所不同的的,这两个函数可以同时阻塞多个I/O操作 。而且可以同时对多个读操作,多个写操作的I/O函数进行检测,直到有数据可读或可写时(注意不是全部数据可读或可写),才真正调用I/O操作函数 。
对于多路复用,也就是轮询多个socket 。多路复用既然可以处理多个IO,也就带来了新的问题,多个IO之间的顺序变得不确定了,当然也可以针对不同的编号 。
在I/O编程过程中,当需要同时处理多个客户端接入请求时,可以利用多线程或者I/O多路复用技术进行处理 。I/O多路复用技术通过把多个I/O的阻塞复用到同一个select的阻塞上,从而使得系统在单线程的情况下可以同时处理多个客户端请求 。与传统的多线程/多进程模型比,I/O多路复用的最大优势是系统开销小,系统不需要创建新的额外进程或者线程,也不需要维护这些进程和线程的运行,降底了系统的维护工作量,节省了系统资源,I/O多路复用的主要应用场景如下:
推荐阅读
- kali linux之应用层Dos
- linux内核驱动第1讲:带你编写一个最简单的字符设备驱动
- Linux常规命令
- 福建安溪铁观音,带你深入了解安溪铁观音茶叶
- 整理 Linux下列出目录内容的命令
- linux系统中socket错误码:eintr和eagain的处理方法
- Linuxfx - 这套Linux操作系统看起来和Windows 10非常类似
- 外网主机A通过带内外网的Linux跳板机B直接访问内网机器C服务
- 带你阅读linux内核源码:下载源码、编译内核并运行一个最小系统
- 你真的理解OAuth2.0协议吗?深入解读OAuth2.0协议