1. Serve one client with each thread/process, and use blocking I/O 这是小程序和java常用的策略,对于交互式的长连接应用也是常见的选择(比如BBS)。 这种策略很能难足高性能程序的需求,好处是实现极其简单,容易嵌入复杂的交互逻 辑。Apache、ftpd等都是这种工作模式。
2. Serve many clients with single thread, and use nonblocking I/O and readiness notification 这是经典模型,datapipe等程序都是如此实现的。优点在于实现较简单,方便移植,也 能提供足够的性能;缺点在于无法充分利用多CPU的机器。尤其是程序本身没有复杂的 业务逻辑时。
3. Serve many clients with each thread, and use nonblocking I/O and readiness notification 对经典模型2的简单改进,缺点是容易在多线程并发上出bug,甚至某些OS不支持多线程 操作readiness notification。
4. Serve many clients with each thread, and use asynchronous I/O 在有AI/O支持的OS上,能提供相当高的性能。不过AI/O编程模型和经典模型差别相当 大,基本上很难写出一个框架同时支持AI/O和经典模型,降低了程序的可移植性。在 Windows上,这基本上是唯一的可选方案。
本文主要讨论模型2的细节,也就是在模型2下应用软件如何处理Socket I/O。 select 与 poll 最原始的同步阻塞 I/O 模型的典型流程如下: 同步阻塞 I/O 模型的典型流程从应用程序的角度来说,read 调用会延续很长时间,应用程序需要相当多线程来解决并发访问问题。
同步非阻塞I/O对此有所改进:经典的单线程服务器程序结构往往如下: do {
Get Readiness Notification of all sockets
int epoll_create(int size) int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout)