Linux socket IO模型

文/人世间(简书做者)
原文连接:http://www.jianshu.com/p/55eb83d60ab1
著做权归做者全部,转载请联系做者得到受权,并标注“简书做者”。

网络应用须要处理的无非就是两大类问题,网络I/O数据计算。相对于后者,网络I/O的延迟,给应用带来的性能瓶颈大于后者。网络I/O的模型大体有以下几种:linux

  • 同步模型(synchronous I/O)
    • 阻塞I/O(bloking I/O)
    • 非阻塞I/O(non-blocking I/O)
    • 多路复用I/O(multiplexing I/O)
    • 信号驱动式I/O(signal-driven I/O)
  • 异步I/O(asynchronous I/O)

网络I/O的本质是socket的读取,socket在linux系统被抽象为流,I/O能够理解为对流的操做。这个操做又分为两个阶段:编程

  1. 等待流数据准备好。
  2. 从内核向进程复制数据。

对于socket流而已,第一步一般涉及等待网络上的数据分组到达,而后被复制到内核的某个缓冲区。第二步把数据从内核缓冲区复制到应用进程缓冲区。服务器

文/人世间(简书做者)
原文连接:http://www.jianshu.com/p/55eb83d60ab1
著做权归做者全部,转载请联系做者得到受权,并标注“简书做者”。

阻塞I/O(bloking I/O)

阻塞I/O是最流行的I/O模型。它符合人们最多见的思考逻辑。阻塞就是进程 "被" 休息, CPU处理其它进程去了(应用程序阻塞,CPU会经过调用add_wait_queue进入等待队列,以后调用schedule调度到其余进程。)。在网络I/O的时候,进程发起recvform系统调用,而后进程就被阻塞了,什么也不干,直到数据准备好,而且将数据从内核复制到用户进程,最后进程再处理数据,在等待数据处处理数据的两个阶段,整个进程都被阻塞。不能处理别的网络I/O。大体以下图:网络

1.png

这就比如咱们去钓鱼,抛竿以后就一直在岸边等,直到等待鱼上钩。而后再一次抛竿,等待下一条鱼上钩,等待的时候,什么事情也不作,大概会胡思乱想吧。异步

非阻塞I/O(non-bloking I/O)

在网络I/O时候,非阻塞I/O也会进行recvform系统调用,检查数据是否准备好,与阻塞I/O不同,"非阻塞将大的整片时间的阻塞分红N多的小的阻塞, 因此进程不断地有机会 '被' CPU光顾"。socket

也就是说非阻塞的recvform系统调用调用以后,进程并无被阻塞,内核立刻返回给进程,若是数据还没准备好,此时会返回一个error。进程在返回以后,能够干点别的事情,而后再发起recvform系统调用。重复上面的过程,循环往复的进行recvform系统调用。这个过程一般被称之为轮询。轮询检查内核数据,直到数据准备好,再拷贝数据到进程,进行数据处理。须要注意,拷贝数据整个过程,进程仍然是属于阻塞的状态。async

2.png
2.png

咱们再用钓鱼的方式来类别,当咱们抛竿入水以后,就看下鱼漂是否有动静,若是没有鱼上钩,就去干点别的事情,好比再挖几条蚯蚓。而后不久又来看看鱼漂是否有鱼上钩。这样往返的检查又离开,直到鱼上钩,再进行处理。分布式

多路复用I/O(multiplexing I/O)

能够看出,因为非阻塞的调用,轮询占据了很大一部分过程,轮询会消耗大量的CPU时间。结合前面两种模式。若是轮询不是进程的用户态,而是有人帮忙就行了。多路复用正好处理这样的问题。性能

多路复用有两个特别的系统调用selectpoll。select调用是内核级别的,select轮询相对非阻塞的轮询的区别在于---前者能够等待多个socket,当其中任何一个socket的数据准好了,就能返回进行可读,而后进程再进行recvform系统调用,将数据由内核拷贝到用户进程,固然这个过程是阻塞的。多路复用有两种阻塞,select或poll调用以后,会阻塞进程,与第一种阻塞不一样在于,此时的select不是等到socket数据所有到达再处理, 而是有了一部分数据就会调用用户进程来处理,也能够理解为"非阻塞"吧。学习

3.png
3.png

对于多路复用,也就是轮询多个socket。钓鱼的时候,咱们雇了一个帮手,他能够同时抛下多个钓鱼竿,任何一杆的鱼一上钩,他就会拉杆。他只负责帮咱们钓鱼,并不会帮咱们处理,因此咱们还得在一帮等着,等他把收杆。咱们再处理鱼。多路复用既然能够处理多个I/O,也就带来了新的问题,多个I/O之间的顺序变得不肯定了,固然也能够针对不一样的编号。

了解了前面三种模式,在用户进程进行系统调用的时候,他们在等待数据到来的时候,处理的方式不同,直接等待,轮询,select或poll轮询,第一个过程有的阻塞,有的不阻塞,有的能够阻塞又能够不阻塞。当时第二个过程都是阻塞的。从整个I/O过程来看,他们都是顺序执行的,所以能够归为同步模型(asynchronous)。都是进程主动向内核检查。

异步I/O(asynchronous I/O)

相对于同步I/O,异步I/O不是顺序执行。用户进程进行aio_read系统调用以后,不管内核数据是否准备好,都会直接返回给用户进程,而后用户态进程能够去作别的事情。等到socket数据准备好了,内核直接复制数据给进程,而后从内核向进程发送通知。I/O两个阶段,进程都是非阻塞的。

4.png
4.png

比以前的钓鱼方式不同,这一次咱们雇了一个钓鱼高手。他不只会钓鱼,还会在鱼上钩以后给咱们发短信,通知咱们鱼已经准备好了。咱们只要委托他去抛竿,而后就能跑去干别的事情了,直到他的短信。咱们再回来处理已经上岸的鱼。

同步和异步的区别

经过对上述几种模型的讨论,须要区分阻塞和非阻塞,同步和异步。他们实际上是两组概念。区别前一组比较容易,后一种每每容易和前面混合。在我看来,所谓同步就是在整个I/O过程。尤为是拷贝数据的过程是阻塞进程的,而且都是应用进程态去检查内核态。而异步则是整个过程I/O过程用户进程都是非阻塞的,而且当拷贝数据的时是由内核发送通知给用户进程。

5.png
5.png

对于同步模型,主要是第一阶段处理方法不同。而异步模型,两个阶段都不同。这里咱们忽略了信号驱动模式。这几个名词仍是容易让人迷惑,只有同步模型才考虑阻塞和非阻塞,由于异步确定是非阻塞,异步非阻塞的说法感受多此一举。

本文所讨论的IO模型来自大名鼎鼎的《unix网络编程:卷1套接字联网API》。单台服务器中的linux系统。分布式的环境或许会不同。我的学习笔记,参考了网络上大多数文章,作了一点小测试。

相关文章
相关标签/搜索