服务器程序通常需要处理三类事件:I/O事件,信号及定时事件.
在此简单介绍一下两种事件处理模式 : Reactor和Procator
首先我们需要明白同步I/O模型通常用于实现Reactor模式,异步I/O模型通常用于实现Procator模式
Reactor模式
- 它要求主线程只负责监听文件描述符上有没有事件发生,立即通知工作线程
- 读写数据等操作均由工作线程来进行完成
工作流程为 - 主线程往epoll内核事件表中注册socket上的读就绪事件
- 主线程调用epoll_wait等待socket上的有数据可读
- 当socket上有数据可读时,epoll_wait通知主线程,主线程则将socket可读事件放入到请求队列之中
- 睡眠在请求队列上的工作线程被唤醒,它从socket读取数据,并处理客户端请求,然后往epoll内核事件表中注册该socket上的写就绪事件
- 主线程调用epoll_wait等待socket可写
- 当socket可写时,epoll_wait通知主线程,主线程将socket可写入事件放入请求队列之中
- 睡眠在请求队列上的某个工作线程被唤醒,它往socket上写入服务器的结果
Procator模式
和Reactor模式不同,Procator模式会将所有的I/O事件交给内核和主线程来进行处理,工作线程只负责程序中的一些业务逻辑处理
使用异步I/O模型来实现Proactor模式的工作流程
- 主线程调用aio_read函数向内核注册socket上的读完成事件,告诉内核用户读的缓冲区位置,已经在完成之后应该如何通知应用程序
- 主线程继续处理其他逻辑
- 当socket上的数据被读入用户缓冲区后,内核将向应用程序发送一个信号,以通知应用程序数据已经很可以使用
- 预定以好的信号处理函数选择一个工作线程来处理客户请求,工作线程处理完客户请求后,调用aio_write函数向内核注册socket上的写完成事件,并告诉内核用户写缓冲区的位置,以及写操作完成后如何通知应用程序
- 主线程继续处理其他逻辑
- 当用户缓冲区的数据被写入socket之后,内核将向应用程序发送一个信号 通知 数据已经发送完毕
- 应用程序预先做好定义的信号处理函数选择工作线程来做善后处理
主线程的epoll_wait调用仅仅用来监听socket上的连接请求事件,不能用来检测连接socket上的读写事件
使用同步I/O同时也可以模拟Proactor模式
- 主线程往epoll内核事件表中注册socket上的读就绪事件
- 主线程调用epoll_wait等待socket上有数据可读
- 当socket上有数据可读时,epoll_wait通知主线程.主线程从socket循环读取数据,直到没有更多数据可读,然后将读取道德数据封装为一个请求对向并且插入到请求队列之中
- 睡眠在请求队列的工作线程被唤醒,它获得请求对象并处理客户请求,然后往epoll内核时间表中注册socket上的写就绪事件
- 主线程调用epoll_wait等待socket可写
- 当socket可写时,epoll_wait通知主线程,主线程往socket上写入服务器处理客户请求的结果