1.什么是IO复用
在《unix网络编程》一书中是这样说的:一种能预先告知内核的能力,使得内核一旦发现进程指定的一个或者多个I/O条件 就绪(也就是输入已经准备好被读取,或者描述符已能承接更多的输出)它就通知进程,这种能力就叫I/O复用。
2.什么时候使用IO复用(网络应用场合)
1)当客户端处理多个描述符(通常是交互式输入和网络套接字),都会发生阻塞,就必须使用I/O复用。
2)如果一个tcp既要处理监听套接字,又要处理已经连接的套接字,一般要用到I/O复用
3)如果一个服务器既要tcp,又要处理udp,一般就要使用I/O复用
4)如果服务器要处理多个服务或者多个协议一般要用到I/O复用
3.I/O复用的模型
在说I/O复用之前,有必要说说I/O模型
在unix下有5中I/O模型 A、阻塞式I/O,B、非阻塞I/O,C、I/O复用(select和epoll等), D 、信号驱动式I/O,F、异步I/O。
阻塞式I/O
在默认情况下所有的套接字都是阻塞的 拿udp通信作为例子 阻塞式I/O 可以由下图表示,在等待数据的过程中系统会将本进程投入睡眠状态,直到返回成功标识。
借用前辈的例子理解阻塞式I/O:就好比我们在京东或者淘宝买了一件宝贝(网络中传递的消息),这件宝贝还在商家(网络的对端)这里,商家会将宝贝交给快递小哥(网络中传递的消息传到了本地内核buf),这时你想要知道宝贝到那个地方了,到底发货了,到了快递员手中(消息到了系统底层的buf中)还是没有,于是你调用了一个方法(recvfrom):打电话给快递小哥,问他货物到他那里了没有,如果你得到的结果是:宝贝已经到你楼下,那自然你就取宝贝了。但是如果快递小哥说还没有宝贝,还得再等等,于是你就跑去睡觉了(进程进入了睡眠状态),因为你知道如果宝贝到了的话快递小哥会给你电话(返回成功指示),这时候你再起床去取件。
非阻塞I/O
把套接字设置为非阻塞是为了通知内核,进程调用recvfrom时,如果没有准备好数据不要将本进程投入到睡眠状态,而是返回一个错误标识。而我们要做的便是:对一个非阻塞描述符不断调用recvfrom,去查看是否有数据准备好,我们把这种方式称为轮询。
应用程序不断轮询内核,查看数据是否准备好,势必会耗费大量的cpu时间。因此会有下面的I/O复用
套用刚才的例子:就好比你不知道宝贝到哪了,于是你隔几秒就打电话给快递小哥,询问宝贝的运输状态。势必会占用了快递小哥的时间,但是对于内核会义不容辞地每次都和说,亲,数据还没准备好哟,要是换做在现实生活,快递小哥都想抽你是吧!
I/O复用
有了I/O复用,可以调用select和epoll等后端(后端这种叫法在libevent中出现)阻塞在这些后端调用之上,而不是真的在IO上发生阻塞。
对于后两者:D 、信号驱动式I/O,F、异步I/O,暂时了解不是很深!这里不做记录。
至于这个举个例子的话,我觉得I/O复用这些机制就好比像 "中集e站" 一样,从不同商家买的东西, 通过不同快递员,最后货品都会放到中集e站中去,由中集e站统一通知你,让你去中集e站取快件!
在不同的系统支持的I/O复用模式有差异,平常用的是linux系统,因此对select和epoll这两种I /O复用模型涉及比较多,而关于这两种复用模型的使用在下篇文章中记录。