高性能服务器程序框架2——事件处理模式

服务器程序通常需要处理三类事件:I/O事件、信号事件、定时事件。

那我就有了一点疑惑,服务器是怎么来处理这些事件的呢?

所以今天呢,就来说说两种高效的事件处理模式:Reactor模式和Proactor模式。

通常使用同步I/O模型(select,poll,epoll 等)用来实现Reactor模式,而异步(aio_read 或aio_write 等)用来实现Proactor模式,不过还可以使用同步来模拟Proactor模式(划重点!!!)。

1. Reactor模式

Reactor模式要求主线程(I/O 处理单元) 只负责监听文件描述上是否有事件发生,有的话就立即将该事件通知工作线程(逻辑单元)。 除此之外,主线程不做任何其他实质性的工作。读写数据,接受新的连接,以及处理客户请求均在工作线程中完成。(个人感觉主线程就像个看门大爷,有事情报告一下就好啦,活儿还挺闲)

Reactor模式的工作流程(以epoll_ wait 为例

(1)主线程往 epoll 内核事件表中注册 socket 上的读就绪事件;

(2)主线程调用 epoll_wait 等待 socket 上有数据可读;

(3)当 socket 上有数据可读时,epoll_wait 通知主线程。主线程则将 socket 上的可读事件放入请求队列;

(4)睡眠在请求队列上的某个工作线程被唤醒,它从 socket 中读取数据,并处理客户请求,然后往 epoll 内核事件表中注册该 socket 上的写就绪事件;

(5)主线程调用 epoll_ wait 等待 socket 可写;

(6)当 socket 可写时,epoll_ wait 通知主线程。主线程将 socket 上的可写事件放入请求队列;

(7)睡眠在请求队列上的某个工作线程被唤醒,它往 socket 上写入服务器处理客户请求结果。

(是不是更觉得主线程的活简单了,有事情发生的话,小弟 epoll_ wait 来通知他一声,他只负责将事情放到请求队列里就完事了)

如下图:

注:工作线程从请求队列中取出事件后,将根据事件的类型来决定如何处理它:1)对于可读事件,执行读数据和处理请求的操作;2)对于可写事件,执行写数据的操作。因此,上图中所示的Reactor模式中,没必要区分所谓的“读工作线程”和“写工作线程”。

2. Proactor模式

Proactor模式将所有的I/O操作都交给主线程和内核来处理,工作线程仅仅用来处理业务逻辑。(比起在Reactor模式下,这次主线程的活可重咯)

Proactor 模式的工作流程是(以aio_ read 和aio_ write 为例):

(1)主线程调用 aio_ read 函数向内核注册 socket 上的读完成事件,并告诉内核用户读缓冲区的位置,以及读操作完成时如何通知应用程序;

(2)主线程继续处理其他逻辑;

(3)当 socket 上的数据被读入用户缓冲区后,内核将向应用程序发送一个信号,以通知应用程序数据已经可用;

(4)应用程序预先定义好的信号处理函数选择一个工作线程来处理客户请求。工作线程处理完客户请求之后,调用 aio_ write 函数向内核注册 socket 上的写完成事件,并告诉内核用户写缓冲区的位置,以及写操作完成时如何通知应用程序;

(5)主线程继续处理其他逻辑;

(6)当用户缓冲区的数据被写入 socket 之后,内核将向应用程序发送一个信号,以通知应用程序数据已经发送完毕;

(7)应用程序预先定义好的信号处理函数选择一个工作线程来做善后处理,比如决定是否关闭 socket。

如下图:

注:在上图中,连接 socket 上的读写事件是通过 aio_ read / aio_ write 向内核注册的,因此内核将通过信号来向应用程序报告连接 socket上的读写事件。所以,主线程中的 epoll_wait 调用仅能用来检测监听 socket 上的连接请求事件,而不能用来检测连接 socket 上的读写事件。

3. 同步I/O模拟Proactor模式

原理:主线程执行数据读写操作,读写完成之后,主线程向工作线程通知这一“ 完成事件”。那么从工作线程的角度来看,它们就直接获得了数据读写的结果,接下来要做的只是对读写的结果进行逻辑处理。

工作流程(以epoll wait 为例):

(1)主线程往 epoll 内核事件表中注册 socket 上的读就绪事件

(2)主线程调用 epoll_wait 等待 socket 上有数据可读

(3)当 socket 上有数据可读时,epoll_wait 通知主线程。主线程从 socket 循环读取数据,直到没有更多数据可读,然后将读取到的数据封装成一个请求对象并插入请求队列

(4)睡眠在请求队列上的某个工作线程被唤醒,它获得请求对象并处理客户请求,然后往 epoll 内核事件表中注册 socket 上的写就绪事件

(5)主线程调用 epoll_wait 等待 socket 可写。

(6)当 socket 可写时,epoll_wait 通知主线程。主线程往 socket 写入服务器处理客户请求的结果

如下图:

 

传送门:

             高性能服务器程序框架1——I/O模型

            高性能服务器程序框架3——并发模式

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值