服务器编程框架
-
IO处理单元 :处理用户连接,读写网络数据;(单机) ;作为接入服务器,实现负载均衡;(集群)
-
请求队列 :各个单元之间通信的抽象,通常被实现为池的一部分;一个单元通知另外一个单元,或者多个单元访问同一个存储单元时,竞争的协调;对于集群来说,请求队列是预先建立的
-
逻辑单元:一个进程或者线程;(单机);一台逻辑服务器;(集群)
-
网络存储单元:可以是数据库,文件,缓存;(单机) ;数据库服务器;(集群)
服务器通常需要处理三种事件:I/O事件,信号事件,定时事件。同步I/O模型常用于实现Reactor,异步I/O模型常用于Proactor。本文整体的介绍高效的事件处理模式
https://blog.csdn.net/enlyhua/article/details/81024206
Reactor
要求主线程(I/O处理单元)只负责监听文件描述符上是否有事件发生,有的话就立即将事件通知工作线程(逻辑单元)数据的读写,接受新的连接以及处理客户请求均在工作线程中完成;除此之外,逻辑线程不作任何工作。
- 主线程往epoll内核事件表中注册socket上的读就绪事件
- 主线程调用epoll_wait等待socket上有数据可读
- 当socket上有数据可读时,epoll_wait通知主线程,主线程则将socket可读事件放入请求队列。
- 睡眠在请求队列上的某个工作线程被唤醒,它从socket读取数据,并处理客户请求,然后往epoll内核事件表中注册该socket上的写就绪事件。
- 主线程调用epoll_wait等待socket可写
- 当socket可写时,epoll_wait通知主线程,主线程将socket可写事件放入请求队列
- 睡眠在请求队列上的某个工作线程(工作线程从请求队列读取事件后,根据事件的类型来决定如何处理它,没有必要区分读工作线程和写工作线程)被唤醒,它往socket上写入服务器处理客户请求的结果
Proactor
Proactor将所有I/O操作都交给主线程和内核来处理,工作线程仅仅负责业务逻辑。使用异步I/O模型(aio_read和aio_write)来实现Proactor模式的工作流程是:
- 主线程调用aio_read向内核注册socket上的读完成事件,并告诉内核用户缓冲区的位置,以及读操作完成时如何通知应用程序(可以用信号)
- 主线程继续处理其他逻辑
- 当socket上的读数据被读入用户缓冲区后,内核向应用进程发送一个信号,已通知应用程序数据已经可用
- 应用进程预先定义好的信号处理函数选择一个工作线程来处理处理客户请求,工作线程处理完客户请求之后,调用aio_write向内核注册socket的完成写事件,并告诉内核用户写缓冲区的位置,以及操作完成时如何通知应用程序(可以用信号)
- 主线程继续处理其他逻辑
- 当用户缓冲区的数据被写入socket之后,内核将向应用程序发送一个信号,已通知应用程序数据已经发送完毕
- 应用程序预先定义好的信号处理函数选择一个工作线程来做善后处理,比如决定是否关闭socket
可使用同步I/O模拟Proactor:主线程执行读数据操作,读完数据之后,主线程向工作线程通知这一“完成事件”,那么从工作线程的角度来看,他们直接获得了读写数据的结果,只需要对读写数据进行处理
- 主线程往epoll内核事件表上注册socket上的读就绪
- 主线程调用epoll_wait等待socket上有数据可读
- 当socket上有数据可读时,epoll_wait通知主线程,主线程从socket上循环读取数据,直到没有更多数据可读,然后将读取到的数据封装成一个请求对象并插入到请求队列
- 睡眠在请求队列上的某个工作线程被唤醒,他获得请求对象并处理客户请求,然后往epoll内核事件表中注册socket上的写就绪
- 主线程调用epoll_wait等待socket可写
- 当socket可写时,epoll_wait通知主线程,主线程往socket上写入服务器处理客户请求结果