Linux网络IO模型

转载自:http://blog.csdn.net/huaishu/article/details/72571660
              http://yaocoder.blog.51cto.com/2668309/1308899


基本概念

同步与异步
       同步和异步关注的是消息通信机制。
       所谓同步,就是在发出一个“调用”时,在没有得到结果之前,该“调用”就不返回。但是一旦调用返回,就得到返回值了。换句话说,就是由“调用者”主动等待这个“调用”的结果。
       而异步则是相反,“调用”在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在“调用”发出后,“被调用者”通过状态、通知来通知调用者,或通过回调函数处理这个调用。
       举个通俗的例子:你打电话问书店老板有没有《分布式系统》这本书,如果是同步通信机制,书店老板会说,你稍等,”我查一下",然后开始查啊查,等查好了(可能是5秒,也可能是一天)告诉你结果(返回结果)。而异步通信机制,书店老板直接告诉你我查一下啊,查好了打电话给你,然后直接挂电话了(不返回结果)。然后查好了,他会主动打电话给你。在这里老板通过“回电”这种方式来回调。

阻塞与非阻塞
       阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态。
       阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。
       非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。
       还是上面的例子,你打电话问书店老板有没有《分布式系统》这本书,你如果是阻塞式调用,你会一直把自己“挂起”,直到得到这本书有没有的结果,如果是非阻塞式调用,你不管老板有没有告诉你,你自己先一边去玩了, 当然你也要偶尔过几分钟check一下老板有没有返回结果。在这里阻塞与非阻塞与是否同步异步无关。跟老板通过什么方式回答你结果无关。


Linux下的五种I/O模型

       1、阻塞I/O(blocking I/O)
       2、非阻塞I/O (nonblocking I/O)
       3、I/O复用(select和poll) (I/O multiplexing)
       4、信号驱动I/O (signal driven I/O (SIGIO))
       5、异步I/O (asynchronous I/O (the POSIX aio_functions))
       前四种都是同步,只有最后一种才是异步IO。

阻塞I/O模型
       默认情况下,所有套接字都是阻塞的。首先明确一下,一次IO包括两个过程:
      (1)等待内核把数据准备好;
      (2)把数据从内核空间copy到用户空间。
       下面以阻塞套接字的recvfrom的的调用图来说明阻塞:
 
       当用户进程调用了recvfrom这个系统调用,kernel就开始了IO的第一个阶段:准备数据。对于network io来说,很多时候数据在一开始还没有到达(比如,还没有收到一个完整的UDP包),这个时候kernel就要等待足够的数据到来。而在用户进程这边,整个进程会被阻塞。当kernel一直等到数据准备好了,它就会将数据从kernel中拷贝到用户内存,然后kernel返回结果,用户进程才解除 block的状态,重新运行起来。
       等待数据的那段过程,就是阻塞。

非阻塞I/O模型
       可以通过设置socket使其变为non-blocking。当对一个non-blocking socket执行读操作时,流程是这个样子:
    
       从图中可以看出,非阻塞IO通过进程反复调用IO函数(多次系统调用,并马上返回);在数据拷贝的过程中,进程是阻塞的。
          当把一个SOCKET接口设置为非阻塞就是告诉内核,当所请求的I/O操作无法完成时,不要将进程睡眠,而是返回一个错误。这样我们的I/O操作函数将不断的测试数据是否已经准备好,如果没有准备好,继续测试,直到数据准备好为止。在这个不断测试的过程中,会大量的占用CPU的时间。
       所以,在非阻塞式IO中,用户进程其实是需要不断的主动询问kernel数据准备好了没有。

I/O复用模型
       I/O多路复用的函数也是阻塞的,但是其与以上两种还是有不同的,I/O多路复用是阻塞在select、poll这样的系统调用之上,而没有阻塞在真正的I/O系统调用如recvfrom之上。这两个函数可以同时对多个读操作,多个写操作的I/O函数进行检测,直到有数据可读或可写时,才真正调用I/O操作函数。
  
        多路复用模型的思想是,当用户进程发起IO请求的时候,将请求到的fd交给内核命令select或者poll去监控,select、poll会采用遍历的方式不断扫描持有的fd,当发现有fd已经就绪的时候,回调函数rollback,但是select、poll函数有两个缺点:
       第一,不断遍历持有的fd,效率低下;
       第二,由于操作系统限制,select、poll函数能管理的fd个数有限制,默认为1024个;
       为此,Linux提供了另一个函数epoll,它采用一种事件驱动的方式来回调rollback函数,这种方式比顺序扫描fd的效率更高,另外,epoll可以管理的fd个数不受操作系统的内核限制,它的最大值只与内存大小有关。详细请参考:http://blog.csdn.net/zero__007/article/details/50672664

信号驱动I/O
       允许套接口进行信号驱动I/O,并安装一个信号处理函数,进程继续运行并不阻塞。当数据准备好时,进程会收到一个SIGIO信号,可以在信号处理函数中调用I/O操作函数处理数据。
       信号驱动的IO模型,最开始不会先调用recvfrom函数,而是去调用sigaction函数,这个函数会生成并执行一个信号处理函数,并且马上返回,此时,应用进程可以继续进行工作,在这个阶段是非阻塞的,当请求的数据报准备就绪时,会生成一个SIGIO的信号通知应用进程调用recvfrom函数完成IO操作,这种模型可以让应用进程在内核准备数据的这段时间内可以继续工作,但是在数据报从内核向用户空间复制的这段时间仍然是阻塞的。


异步I/O
         异步I/O模型是由应用程序告知内核需要进行那些操作,由内核来完成所有的操作(包括数据报的准备和向用户空间的复制等),内核完成所有操作之后,通知应用进程开始处理数据报。
 
        如上图,用户进程发起read操作之后,立刻就可以开始去做其它的事。而另一方面,从kernel的角度,当它受到一个asynchronous read之后,首先它会立刻返回,所以不会对用户进程产生任何block。然后,kernel会等待数据准备完成,然后将数据拷贝到用户内存,当这一切都 完成之后,kernel会给用户进程发送一个signal,告诉它read操作完成了。
       从工作流程上来看,信号驱动的IO模型和异步IO模型,差别在于通知应用进程的时机,信号驱动IO模型的时机是在IO的数据报准备就绪之后,将数据从内核复制到用户空间之前,而异步IO模型是在数据报复制到用户空间完成之后;这里的异步指的是内核进程和应用进程之间的异步;
       从驱动方式上来看,信号驱动的IO模型的驱动载体是fd,即数据准备就绪之后触发,而异步IO模型的驱动载体是事件,即当整个操作完成之后触发。


相关链接:http://blog.csdn.net/zero__007/article/details/50511827




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值