- 阻塞IO:在内核将数据准备好之前,系统调用会一直等待,所有的套接字,默认都是阻塞方式。
- 非阻塞IO往往需要程序员循环的方式反复尝试读写文件描述符,这个过程称为
轮训. 这对CPU来说是较大的浪费,只有特定的场景下才使用。
- 内核将数据准备好的时候,使用SIGIO信号通知应用程序进行IO操作。
- 从流程上看类似于阻塞IO,但是实际最核心在于IO多路转接能够同时等待多个文件描述符就绪状态。
- 友内核在数据拷贝完成时,通知应用程序(而信号驱动是高职应用程序合适可以开始拷贝数据)。
- 同步和异步关注的是消息通信机制
- 所为同步,就是在发出一个调用时,在没有得到结果之前,该调用就不返回。但是一旦调用返回,就得到返回值了;换句话说,就是主动调用者主动等待这个调用的结果。
- 异步则是相反,调用在发出后,这个调用就直接返回了,所以没有返回结果;换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果;而是在调用发出后,被调用者通过状态来通知调用者,或者通过回调函数处理这个调用。
阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态。
- 阻塞调用时指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才返回。
- 非阻塞调用指不能立刻返回得到结果之前,该调用不会阻塞当前线程。
一个文件描述符,默认都是阻塞IO。
函数原型如下

传入的 cmd 的值不同,后面追加的参数也不相同。
fcntl 函数有5种功能:
- 复制一个现有的文件描述符(cmd = F_DUPFD).
- 获得/设置文件描述符标记(cmd = F_GETFD/F_SETFD).
- 获得/设置文件状态标记(cmd = F_GETFL/F_SETFL).
- 获得/设置异步IO所有权(cmd = F_GETOWN/SETOWN).
- 获得/设置记录锁(cmd = F_GETLK、F_SETLK/F_SETLKW).
基于fcntl,实现一个SetNoBlock函数,将文件描述符设置为非阻塞.


- select 的函数原型如下
#include








注意: fd_set的大小可以调整,可能涉及到重新编译内核.



poll 函数接口


不同于select使用三个位图来表述三个fdset的方式,poll使用一个pollfd指针实现.
- pollfd 结构包含了要监视的fd和发生的event,不再声依永select 参数-值传递方式。 还是用比select更方便。
- poll并没有最大数量限制(但是数量过大后性能也会下降)。


epoll 友三个相关的系统调用


struct epoll_event 结构如下




- 每个epoll对象都有一个独立的eventpoll结构体,用于存放通过epool_ctl方法想epoll对象中添加进来的事件。
- 这些事件都会挂载在红黑树中,如此重复添加的事件就可以通过红黑树而高效的识别出来。
- 而所有添加的epoll中的事件都会与设备(网卡)驱动程序建立回调关系,也就是说,当响应事件发生时会调用这个回调方法。
- 这个会回调方法在内核中叫 ep_epoll_callback,它会将繁盛的事件添加到rdlist双向链表中。
- 在epoll中,对于每一个事件,都会建立一个epitem结构体。



epoll 有 2 中工作方式-水平触发(LT) 和边缘触发(ET)



使用 ET 模式的 epoll, 需要将文件描述设置为非阻塞. 这个不是接口上的要求, 而是 “工程实践” 上的要求.
假设这样的场景: 服务器接受到一个10k的请求, 会向客户端返回一个应答数据. 如果客户端收不到应答, 不会发送第二个10k请求.

如果服务端写的代码是阻塞式的read, 并且一次只 read 1k 数据的话(read不能保证一次就把所有的数据都读出来,参考 man 手册的说明, 可能被信号打断), 剩下的9k数据就会待在缓冲区中.

此时由于 epoll 是ET模式, 并不会认为文件描述符读就绪. epoll_wait 就不会再次返回. 剩下的 9k 数据会一直在缓冲区中. 直到下一次客户端再给服务器写数据. epoll_wait 才能返回。



参考网址 http://blog.csdn.net/fsmiy/article/details/36873357













