|面试官问我Linux的网络IO模式怎么办?( 二 )


|面试官问我Linux的网络IO模式怎么办?
本文插图

进程发起调用后就一直等待 , 也就是阻塞状态 。
等到数据拷贝完成后 , 进程还不能运行 , 需要内核给一个 ok 的信号 , 告诉进程数据已经拷贝到你那里了 , 用户进程这才解除阻塞状态 , 愉快的运行起来 。
所以很明显 , 阻塞 I/O的特点是内核返回数据拷贝完成的信号之前 , 进程一直被阻塞 。 也就是说阻塞其实包括两个阶段 , 一个是等待数据准备 , 一个是数据从内核空间拷贝到用户空间
ok , 理解了阻塞 I/O 的调用过程后 , 接下来的I/O模式就很简单了
非阻塞 I/O
和「阻塞 I/O」不同的是 。 「非阻塞 I/O」的进程发起一个read调用时 , 如果内核的数据还没有准备好 , 它就会立刻返回一个error信号 。
从用户进程的角度讲 , 它发起一个read操作后 , 并不需要等待就马上得到了一个结果 , 当用户进程判断结果是一个error时 , 它知道数据还没有准备好 , 于是再次发送read调用 , 一遍又一遍地询问 。
当内核运算完毕准备好数据 , 并且再次收到用户进程的调用时 , 它就马上把数据拷贝到用户空间里 , 然后返回ok信号
|面试官问我Linux的网络IO模式怎么办?
本文插图

所以「非阻塞 I/O」的特点是 , 用户进程不断询问内核 , 数据好了没有
I/O 多路复用
「I/O 多路复用」实际上是「阻塞 I/O」的变种 。
select , poll , epoll都是「I/O 多路复用」的机制 , 它的好处在于单个进程就可以同时处理多个网络连接的IO
单个进程处理多个网络连接??!
没错 , 比如select方法 。 用户进程先调用select方法 , select干了两件事 , 一个是管理多个负责网络连接的socket , 另一个是让内核监视socket的状态
当内核接收到socket返回的数据并运算完成后 , select方法就会返回 , 这时用户进程再发起read调用 , 把数据从内核空间拷贝到用户空间里
|面试官问我Linux的网络IO模式怎么办?
本文插图

需要注意的是 , socket本身是非阻塞的 , 但整个用户进程是阻塞的 。
这种阻塞包括两个阶段 , 一个是发起select方法等待socket返回数据时阻塞 , 另一个是等待数据从内核控件拷贝到用户空间时阻塞 , 从这就可以看出和「阻塞 I/O」其实是一样的
所以 , 「I/O 多路复用」的特点是一个进程可以同时等待多个信号 , 任意一个信号就绪时发起系统调用
异步 I/O
终于到最后一个啦 , 加油加油!
区别于上面几种I/O模式 , 「异步 I/O」是没有阻塞的
用户进程发起read调用之后 , 立刻就可以开始去做其它的事 。 内核会立刻返回 , 所以不会对用户进程产生任何阻塞 。
当内核数据计算完成后 , 它会自动把数据拷贝到用户空间 , 然后再给用户进程发送一个信号 , 告诉它read调用完成了 。 所以用户进程并不是在收到ok信号后拷贝数据 , 数据拷贝阶段也不会阻塞
|面试官问我Linux的网络IO模式怎么办?
本文插图

所以「异步 I/O」的特点是 , 用户进程不需要等待内核返回的信号 , 一直运行
总结
终于介绍完啦
总结一下
阻塞io和非阻塞io的区别是
内核准备数据时有没有立即返回 。
阻塞io只有在内核准备好数据后才返回 , 而非阻塞io在准备过程中一直返回 。
同步io和异步io的区别
同步io会阻塞进程 , 异步io不会阻塞进程
所以其实「阻塞 I/O」 , 「非阻塞 I/O」和「I/O 多路复用」都是同步I/O


推荐阅读