找回密码
 立即注册
  • QQ空间
  • 回复
  • 收藏

真正涨知识了!Linux五大网络IO模型详解

admin 2020-1-15 17:42 120人围观 Linux相关



01

什么是IO?


IO模型中,先讨论下什么是IO?

IO在计算机中指的就是Input/Output(输入/输出)。Input/Output(输入/输出)的内容当然就是data(数据)了。

那么数据被Input到哪,Output到哪呢?


  • Input(输入)数据到内存中,Output(输出)数据到IO设备(磁盘、网络等需要与内存进行数据交互的设备)中;

  • IO设备与内存直接的数据传输通过IO接口,操作系统封装了IO接口,我们编程时可以直接使用

02

阻塞/非阻塞与同步/异步


阻塞/非阻塞


针对的对象是调用者自己本身的情况

☞ 阻塞


指调用者在调用某一个函数后,一直在等待该函数的返回值,线程处于挂起状态。

☞ 非阻塞


指调用者在调用某一个函数后,不等待该函数的返回值,线程继续运行其他程序(执行其他操作或者一直遍历该函数是否返回了值)

同步/异步


针对的对象是被调用者的情况

☞ 同步


指的是被调用者在被调用后,操作完函数所包含的所有动作后,再返回返回值

☞ 异步


指的是被调用者在被调用后,先返回返回值,然后再进行函数所包含的其他动作。

03

五种IO模型



recvfrom/recv都是操作系统的内核函数,用于从(已连接)socket上接收数据,并捕获数据发送源的地址。

recv函数原型:ssize_t recv(int sockfd, void *buff, size_t nbytes, int flags)

sockfd:接收端套接字描述符

buff:用来存放recv函数接收到的数据的缓冲区

nbytes:指明buff的长度

flags:一般置为0

对于一个应用程序即一个操作系统进程来说,它既有内核空间(与其他进程共享),也有用户空间(进程私有),它们都是处于虚拟地址空间中。用户进程是无法访问内核空间的,它只能访问用户空间,通过用户空间去内核空间复制数据,然后进行处理。

阻塞io(同步io):

发起请求就一直等待,直到数据返回。好比你去商场试衣间,里面有人,那你就一直在门外等着。(全程阻塞)




BIO程序流
应用程序调用一个IO函数,导致应用程序阻塞,等待数据准备好。如果数据没有准备好,一直等待….数据准备好了,从内核拷贝到用户空间,IO函数返回成功指示。

当调用recv()函数时,系统首先查是否有准备好的数据。如果数据没有准备好,那么系统就处于等待状态。当数据准备好后,将数据从系统缓冲区复制到用户空间,然后该函数返回。在套接应用程序中,当调用recv()函数时,未必用户空间就已经存在数据,那么此时recv()函数就会处于等待状态。

非阻塞io(同步io):

不管有没有数据都返回,没有就隔一段时间再来请求,如此循环。好比你要喝水,水还没烧开,你就隔段时间去看一下饮水机,直到水烧开为止。(复制数据时阻塞)




非阻塞IO程序流

非阻塞IO通过进程反复调用IO函数(多次系统调用,并马上返回);在数据拷贝的过程中,进程是阻塞的;

我们把一个SOCKET接口设置为非阻塞就是告诉内核,当所请求的I/O操作无法完成时,不要将进程睡眠,而是返回一个错误。这样我们的I/O操作函数将不断的测试数据是否已经准备好,如果没有准备好,继续测试,直到数据准备好为止。在这个不断测试的过程中,会大量的占用CPU的时间。

io复用(同步io):

I/O是指网络I/O,多路指多个TCP连接(即socket或者channel),复用指复用一个或几个线程。意思说一个或一组线程处理多个连接。比如课堂上学生做完了作业就举手,老师就下去检查作业。(对一个IO端口,两次调用,两次返回,比阻塞IO并没有什么优越性;关键是能实现同时对多个IO端口进行监听,可以同时对多个读/写操作的IO函数进行轮询检测,直到有数据可读或可写时,才真正调用IO操作函数。) 




IO多路复用程序流
select和epoll;对一个socket,两次调用,两次返回,比阻塞IO并没有什么优越性;

关键是能实现同时对多个socket进行处理。

I/O复用模型会用到select、poll、epoll函数,这几个函数也会使进程阻塞,但是和阻塞I/O所不同的的,这两个函数可以同时阻塞多个I/O操作。而且可以同时对多个读操作,多个写操作的I/O函数进行检测,直到有数据可读或可写时,才真正调用I/O操作函数。

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

这个图和blocking IO的图其实并没有太大的不同,事实上还更差一些。因为这里需要使用两个系统调用(select和recvfrom),而blocking IO只调用了一个系统调用(recvfrom)。但是,用select的优势在于它可以同时处理多个connection。

(select/epoll的优势并不是对于单个连接能处理得更快,而是在于能处理更多的连接。)

信号驱动io(同步io):

事先发出一个请求,当有数据后会返回一个标识回调,这时你可以去请求数据。好比银行排号,当叫到你的时候,你就可以去处理业务了(复制数据时阻塞)。




信号驱动IO程序流

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

两次调用,两次返回;

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

异步io:

发出请求就返回,剩下的事情会异步自动完成,不需要做任何处理。好比有事秘书干,自己啥也不用管。  



当一个异步过程调用发出后,调用者不能立刻得到结果。

实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者的输入输出操作。

总结:



五种IO的模型:阻塞IO、非阻塞IO、多路复用IO、信号驱动IO和异步IO;前四种都是同步IO,在内核数据copy到用户空间时都是阻塞的。

阻塞IO和非阻塞IO的区别在于第一步,发起IO请求是否会被阻塞,如果会那就是传统的阻塞IO,如果不会那就是非阻塞IO。

同步IO和异步IO的区别就在于第二个步骤是否阻塞,如果实际的IO读写阻塞请求进程,那么就是同步IO;如果不阻塞,而是操作系统帮你做完IO操作再将结果返回给你,那么就是异步IO。

-END-



推荐阅读

【01】Linux与windows相比究竟好在哪里?【02】最全盘点,哪款 Linux 桌面系统是你的菜?
【03】2020,Linux会有哪些新发展?【04】Unix 和 Linux 你不知道的那些历史【05】学会Linux正则表达式,我只用了3分钟


免责声明:整理文章为传播相关技术,版权归原作者所有,如有侵权,请联系删除




----------------------------------------------------------------------------------------------------------------------
我们尊重原创,也注重分享,文章来源于微信公众号:嵌入式ARM,建议关注公众号查看原文。如若侵权请联系qter@qter.org。
----------------------------------------------------------------------------------------------------------------------

鲜花

握手

雷人

路过

鸡蛋

yafeilinux和他的朋友们微信公众号二维码

微信公众号

专注于Qt嵌入式Linux开发等。扫一扫立即关注。

Qt开源社区官方QQ群二维码

QQ交流群

欢迎加入QQ群大家庭,一起讨论学习!

我有话说......