服务器程序通常需要处理三类事件:I/O事件、信号和定时事件。随着网页设计模式的兴起,Reactor和Proactor事件处理模式应运而生。同步I/O模型通常用于实现Reactor模式,异步I/O模型用于实现Rroactor模式。1.Reactor模式 Reactor模式要求主线程(I/O处理单元)只负责监听文件描述符上是否有事件发生,一旦有事件立即通知工作线程(逻辑单元).除此之外,主线程不做任何其他实质性工作。读取和写入数据、接受新连接和处理客户端请求都在工作线程中完成。 使用同步I/O模型(以epoll_wait为例)实现的Reactor模式的工作流程是:主线程在epoll内核事件表中注册socket上的readready事件。主线程调用epoll_wait等待socket上的数据读取。当socket上有数据可读时,epoll_wait通知主线程。主线程将socket可读事件放入请求队列。一个休眠在请求队列上的工作线程被唤醒,它从socket中读取数据,处理客户端请求,然后在epoll内核事件表中注册socket上的write-ready事件。主线程调用epoll_wait等待套接字可写。当套接字可写时,epoll_wait通知主线程。主线程将套接字可写事件放入请求队列。一个休眠在请求队列上的工作进程被唤醒,它将服务器处理客户端请求的结果写入套接字。 工作线程从请求队列中取出事件后,会根据事件类型决定如何处理:对于可读事件,执行读取数据和处理请求的操作;对于可写事件,执行写入数据的操作。因此,不需要区分Reactor模式下所谓的“读工作线程”和“写工作线程”。2.Proactor模式 不同于Reactor模式。Proactor模式下,所有的I/O操作都交给主线程和内核处理,工作线程只负责业务逻辑。 使用异步I/O模型(以aio_read和aio_write为例)实现的Proactor模式的工作流程是:主线程调用aio_read函数向内核注册socket上的读完成事件,并告诉内核用户读缓冲区的位置,以及读操作完成后如何通知应用程序(这里以信号为例),主线程继续处理其他逻辑。当socket上的数据读入用户缓冲区后,内核会向应用程序发送一个信号,通知应用程序数据可用。应用程序的预定义信号处理函数选择一个工作线程来处理客户端请求。工作线程处理完客户端请求后,调用aio_write函数向内核注册socket上的写完成事件,并告诉内核用户写缓冲区的位置,写操作完成时如何通知应用程序完成(仍以信号为例),主线程继续处理其他逻辑用户缓冲区中的数据写入套接字后,内核会向应用程序发送信号,通知应用程序数据已发送.应用程序预定义的信号处理函数选择一个工作线程做后续处理,比如决定是否关闭socket。 connectionsocket上的读写事件是通过aio_read/aio_write向内核注册的,所以内核会通过信号将connectionsocket上的读写事件上报给应用程序。因此,主线程中的epoll_wait调用只能用来检测监听socket上的连接请求事件,而不能检测socket上的读写事件。
