最近工做接触到了网络服务同步和异步,因此学习了下《UNIX网络编程》,在此做下总结。编程
输入/输出(I/O)是在主存和外部设备(如磁盘驱动器、终端和网络)之间拷贝数据的过程。输入是从I/O设备拷贝数据到主存,而输出是从主存拷贝数据到I/O设备。好比,网络可视为一个I/O设备,做为数据源和数据接收方。系统能够通过网络读取其余机器发送来的数据,并将数据复制到本身主存中。 网络
下面分别介绍Unix的5种I/O模型:多线程
一个输入操做一般为如下两个阶段:异步
(1)等待数据准备好;socket
(2)从内核复制数据到进程;函数
拿网络中客户端请求服务的例子说明五种模型。学习
在网络请求中,套接字(socket)是实现通讯的一个端点,应用程序能够经过它发送或接收数据,可对其进行像对文件同样的打开、读写和关闭等操做。线程
对于一个soket上的输入操做:3d
(1)等待数据从网络中到达。数据到达时被复制到内核中的缓冲区;指针
(2)把数据从内核缓冲区复制到应用进程缓冲区。
阻塞式IO模型是最经常使用的,咱们将recvfrom做为系统调用,来观察应用进程和内核之间的区别。下图中进程调用recvfrom,该系统调用直到数据报准备好且拷贝到应用缓冲区或者出错才返回,也就是说在数据返回以前,进程被阻塞,当进程返回成功指示后,才能够开始下面的处理。
下图中,前三次调用recvfrom,数据还没准备好,内核会当即返回一个EWOULDBLOCK错误,直到第四次调用时,数据准备好被拷贝到应用缓冲区,该系统调用返回成功指示,接下来开始处理数据。当应用进程像这样对一个非阻塞描述字循环调用recvfrom时,这实际上就是轮询(polling)。
应用程序不断地查询内核,检查数据是否准备好,这对CPU来讲是一种浪费,因此这种模型比较少见。
IO复用是指经过调用select,poll或者epoll函数,监听多个socket链接,每新来一个socket链接,就会被加入到监听列表,实现单个线程同时处理多个网络链接的IO。基本原理是经过select,poll或epoll不断轮询负责的所有socket,当其中一个数据准备好,就通知进程。而后调用recvfrom拷贝数据从内核到进程,返回成功指示后,进行下一步处理。
应用进程虽然不会被socket的IO阻塞,但一直被select,poll或epoll阻塞。若是socket数不是不少的话,使用IO复用模型可能比多线程 + 阻塞IO延迟更大,由于IO复用模型相对比以前的模型须要两次系统调用,它的优点在于能处理较多的链接。
该模型经过系统调用sigaction安装一个信号处理程序。当内核准备好数据后,发送信号告知进程。在信号处理程序中调用recvfrom读取数据,并通知主循环。这种模型的好处是当等待数据报到达时,IO不被阻塞。主循环能够继续执行,只是等待信号处理程序的通知:数据已准备好被读。
异步IO模型让内核完成整个操做(包括将数据从内核拷贝到进程缓冲区)后才进行通知应用进程。这个模型和信号驱动模型的主要区别在于:信号驱动IO是由内核通知咱们什么时候能够启动一个IO操做,而异步IO是由内核通知咱们IO操做什么时候完成。
下图中调用aio_read,传递内核描述字、缓冲区指针、缓冲区大小、文件偏移,并告诉内核整个操做完成时如何通知咱们。该系统调用当即返回,不阻塞于IO操做。该图中,内核在操做完成后传递一个信号,该信号直到数据被拷贝到缓冲区才产生,这是和信号驱动IO的不一样之处。
从这两个阶段来看,前四种模型在第一阶段有所不一样,但第二个阶段基本相同,把数据从内核拷贝到应用进程的缓冲区时,进程被阻塞于recvfrom调用。异步IO模型的两个阶段都不一样于前四种模型。
同步IO操做会阻塞请求进程,直到IO操做完成。
异步IO操做不会阻塞请求进程。
前四种模型:阻塞IO模型、非阻塞IO模型、IO复用模型和信号驱动IO都是同步IO模型,由于真正的IO操做(recvfrom)阻塞进程。