五种网络IO模型总结

文章目录

    • 概述
    • POSIX
    • 简述阻塞、非阻塞、同步、异步
      • 阻塞和非阻塞
      • 同步/异步IO
      • 同异步io和阻塞非阻塞io的区别
    • IO多路复用
    • 异步
    • 信号驱动
    • 总结比较下五种IO模型
    • 总结

概述

在网络上看到很多关于阻塞IO、非阻塞IO、同步IO、异步IO的例子,总觉得写的过于复杂并且让人难以理解。于是我把我自己把这几个概念的理解写下来以供参考。

POSIX

POSIX(可移植操作系统接口)把同步IO操作定义为导致进程阻塞直到IO完成的操作,反之则是异步IO
I/O 操作一般分为两个部分:

  • 阶段1:应用程序发起 I/O 操作请求,等待数据,或者将要操作的数据拷贝到系统内核中(比如 socket)。
  • 阶段2:系统内核进行 I/O 操作(一般是内核将数据拷贝到用户进程中)。

简述阻塞、非阻塞、同步、异步

阻塞和非阻塞

阻塞和非阻塞发生在请求处,也就是阶段1 ,关注的是程序在等待调用结果时的状态。

  • 阻塞是指调用结果返回之前,当前进程(线程)会被挂起,调用进程(线程)会阻塞在IO请求处,直到IO操作请求完成,数据到来,最重要的是用户进程的函数在请求过程中不会返回。
    五种网络IO模型总结_第1张图片

    • eg:recv()函数默认是阻塞的,什么是阻塞呢?就是当你调用recv()函数时,整个进程或者线程就等待在这里了,直到你recv的fd的所有信息都被send过来,这么做好处就是保证所有信息都能够完整的读取了,但劣势也很明显,就是在recv()的过程中你的进程或线程做不了其它事情,由此,引入了非阻塞IO。
  • 非阻塞调用是指在不能立刻得到结果之前,该调用不会阻塞进程(线程),进程(线程)可以去干别的事情,一般使用轮询的方法来查询IO操作的数据是否准备好了。
    五种网络IO模型总结_第2张图片

    • eg:以recv()函数为例,当你将其设置为非阻塞时,每次当你recv()时,就直接返回,不管信息有没有完全send进来,好处很明显,recv()了之后进程马上能处理下一行代码,坏处也很明显,就是你不知道你的消息是否读完了,这种问题就是TCP中大名鼎鼎的半包问题(解决办法主要是通过一个buffer缓存所有读进来的消息)
  • 当使用I/O 多路复用的时候,用户的 I/O 操作会立即返回,但会利用 select 和 epoll 等方法对所监视的 I/O 操作描述符进行遍历轮询(此操作是为了检查数据是否准备完毕,也就是 I/O 操作的阶段1,同时此操作是阻塞,进程或者线程需要等待轮询结果的返回),查看可用的句柄并返回。然后用户进程再对其进行操作。

同步/异步IO

  • 同步和异步关注的是消息通信机制,具体来说就是调用者是否等待调用结果的返回,对于 I/O 操作而言,就是应用程序是否等待 I/O 操作完成。
    • eg: 以recv()函数为例, 不管 是否设置为阻塞还是非阻塞(阶段1),都有一个将内核数据拷贝到用户进程的I/O操作(阶段2),如果用户进程等待I/O操作返回,则为同步,反之则为异步。

同异步io和阻塞非阻塞io的区别

结合前面的概念,可以看出,其实这两者存在本质的区别,它们的修饰对象是不同的

  • 阻塞和非阻塞是指进程访问的数据如果尚未就绪,进程是否需要等待,简单说这相当于函数内部的实现区别,也就是未就绪时是直接返回还是等待就绪。
  • 同步和异步是指访问数据的机制,同步一般指主动请求并等待 I/O 操作完毕的方式,当数据就绪后在读写的时候必须等待异步则指主动请求数据后便可以继续处理其它任务,随后等待 I/O,操作完毕的通知,这可以使进程在数据读写时也不阻塞。

只有同步的时候,才会有是否阻塞之说

IO多路复用

这里在调用recv前先调用select或者poll,这两个个系统调用都可以在内核准备好数据(网络数据到达内核)时告知用户进程,这个时候再调用recv一定是有数据的。因此这一过程中它是阻塞于selectpoll,而没有阻塞于recv,有人将非阻塞IO定义成在读写操作时没有阻塞于系统调用的IO操作(不包括数据从内核复制到用户空间时的阻塞,因为这相对于网络IO来说确实很短暂),如果按这样理解,这种IO模型也能称之为非阻塞IO模型,但是按POSIX来看,它也是同步IO,称之为同步非阻塞IO。

这种IO模型比较特别,分个段。因为它能同时监听多个文件描述符(fd)。当有文件描述符有就绪事件时,则返回就绪事件的文件描述符来进行读写。
五种网络IO模型总结_第3张图片

异步

调用aio_read,让内核等数据准备好,并且复制到用户进程空间后执行事先指定好的函数。整个过程没有recv,这才是真正的异步IO。
五种网络IO模型总结_第4张图片

信号驱动

通过调用sigaction注册信号函数,等内核数据准备好的时候系统中断当前程序,执行信号函数(在这里面调用recv)。是不是很像异步IO?很遗憾,它还是同步IO(省不了数据从内核拷贝到用户空间的操作)。
五种网络IO模型总结_第5张图片

总结比较下五种IO模型

五种网络IO模型总结_第6张图片

总结

IO分两阶段:

1.数据准备阶段
2.内核空间复制回用户进程缓冲区阶段

一般来讲:阻塞IO模型、非阻塞IO模型、IO复用模型(select/poll/epoll)、信号驱动IO模型都属于同步IO,因为阶段2是阻塞的(尽管时间很短)。只有异步IO模型是符合POSIX异步IO操作含义的,不管在阶段1还是阶段2都可以干别的事。

ps:以上图片均截自UNIX网络编程卷1。

你可能感兴趣的:(网络编程,网络,同步/异步,阻塞/非阻塞,IO多路复用,select/epoll)