浅谈几种服务器端模型——反应堆模式(基于epoll的反应堆)
2012-04-25 21:11
288 查看
引言:前面一章简单介绍了关于epoll 的使用方式,这一章介绍一下一个简单的反应堆模型,没有实现超时机制的管理。最主要的是要介绍一下关于异步事件反应堆的设计方式。
反应堆的模型图在上一张可以看到,但是那个是盗来的一张图,twisted 的反应堆。今天给不熟悉这个部分的朋友介绍一下基于 epoll 的反应堆,过程类似于libevent.
反应堆可以提供几个操作:
(0)创建一个反应堆:
?
返回一个操作句柄.
(1)为某一个需要监听的文件描述符加入回调函数,并注册事件类型。
?
这里的 revent 由宏定义为几种类型:
?
相应的操作可以使用 | 运算来并几个需要监听的事件类型。
事件类型定义如下:
?
事件结构本身后面解释。
(2)将需要监听的并且已经初始化的事件加入反应堆。
?
将刚才注册了事件类型和回调函数的事件加入 base, 即将其看做一个反应堆。
(3)最后提供了一个 dispatch 函数,反应堆开始循环,等待事件的发生。如果对应的 fd 上的事件发生,调用相应的回调函数。由第一步注册。
?
反应堆支持在循环过程中,通过相应的回调函数再注册事件,类似于热加入,热移除。
实现方式很简单,就是在第一个事件的回调函数上调用 mc_event_set()然后注册。再加入 base.
base 的结构如下 :
?
让我们来看一个简单的 demo
?
首先:封装的几个套接口操作没有考虑错误处理,作为简单的实例。
定义了一个 connection 结构,用于表示每一个到来的连接,这里的 struct _connection 中包含读写事件和一个缓冲区,还有指向反应堆的指针和对应注册的fd
工作过程如下:(集中看 main函数)
(1)创建一个反应堆。
(2)实例化一个 connection
(3)创建套接口,bind,listen 老生常谈,这里就不多说了
(4)将这个监听套接口注册相应的回调函数,这里我们注册的是 handler_accept() 函数,回调函数类型都是 void *XXX( int , short , void *) ;
当监听套接口发生可读事件时,第一次我们认为是相应的监听套接口得到了新的连接,所以,第一次调用的时候直接调用注册了的回调函数 handler_accept().
在handler_accept() 函数中,我们为这个连接的读写事件添加了相应的回调函数,并把连接描述符(不是监听描述符)注册到这个上。下次这个套接口可读的时候调用handler_read(),可写的时候调用handler_write(). 如果需要改变状态或改变回调函数,只需要一个状态机或者别的方式来确定需要的回调函数是哪一个,在我们的handler_write() 和 handler_read()中可以改变回调函数,代码所示。
PS:注意一点的是我们的事件是一个实例,不管是在connection结构中或是自己定义,都需要不断的向操作系统申请空间,如果采用对象池或者connection池的方式,可以减少服务器的负载。
总结:反应堆模式最基本的操作就是:注册事件(为需要监听的fd加入回调函数)----->将事件加入反应堆------>开始事件循环------>事件发生,调用回调函数。
异步操作的精髓就是在这里,而不是同步的等待每一个事件。下一章讲解这个反应堆的实现,越来越带感咯.
反应堆的模型图在上一张可以看到,但是那个是盗来的一张图,twisted 的反应堆。今天给不熟悉这个部分的朋友介绍一下基于 epoll 的反应堆,过程类似于libevent.
反应堆可以提供几个操作:
(0)创建一个反应堆:
?
(1)为某一个需要监听的文件描述符加入回调函数,并注册事件类型。
?
?
事件类型定义如下:
?
(2)将需要监听的并且已经初始化的事件加入反应堆。
?
(3)最后提供了一个 dispatch 函数,反应堆开始循环,等待事件的发生。如果对应的 fd 上的事件发生,调用相应的回调函数。由第一步注册。
?
实现方式很简单,就是在第一个事件的回调函数上调用 mc_event_set()然后注册。再加入 base.
base 的结构如下 :
?
?
首先:封装的几个套接口操作没有考虑错误处理,作为简单的实例。
定义了一个 connection 结构,用于表示每一个到来的连接,这里的 struct _connection 中包含读写事件和一个缓冲区,还有指向反应堆的指针和对应注册的fd
工作过程如下:(集中看 main函数)
(1)创建一个反应堆。
(2)实例化一个 connection
(3)创建套接口,bind,listen 老生常谈,这里就不多说了
(4)将这个监听套接口注册相应的回调函数,这里我们注册的是 handler_accept() 函数,回调函数类型都是 void *XXX( int , short , void *) ;
当监听套接口发生可读事件时,第一次我们认为是相应的监听套接口得到了新的连接,所以,第一次调用的时候直接调用注册了的回调函数 handler_accept().
在handler_accept() 函数中,我们为这个连接的读写事件添加了相应的回调函数,并把连接描述符(不是监听描述符)注册到这个上。下次这个套接口可读的时候调用handler_read(),可写的时候调用handler_write(). 如果需要改变状态或改变回调函数,只需要一个状态机或者别的方式来确定需要的回调函数是哪一个,在我们的handler_write() 和 handler_read()中可以改变回调函数,代码所示。
PS:注意一点的是我们的事件是一个实例,不管是在connection结构中或是自己定义,都需要不断的向操作系统申请空间,如果采用对象池或者connection池的方式,可以减少服务器的负载。
总结:反应堆模式最基本的操作就是:注册事件(为需要监听的fd加入回调函数)----->将事件加入反应堆------>开始事件循环------>事件发生,调用回调函数。
异步操作的精髓就是在这里,而不是同步的等待每一个事件。下一章讲解这个反应堆的实现,越来越带感咯.
相关文章推荐
- 浅谈几种服务器端模型——反应堆模式(epoll 简介)
- [原]浅谈几种服务器端模型——反应堆模式(epoll 简介) - _Boz - 博客园
- 浅谈几种服务器端模型——epoll
- 浅谈几种服务器端模型——同步阻塞迭代
- 浅谈几种服务器端模型——同步阻塞迭代
- [原]浅谈几种服务器端模型——多线程并发式(线程池)
- 浅谈几种服务器端模型——多进程并发式
- ]浅谈几种服务器端模型——多线程并发式(线程池)
- 浅谈几种服务器端模型——多线程并发式(线程池)
- 浅谈几种服务器端模型——多线程并发式(线程池)
- Netty学习之旅------线程模型前置篇Reactor反应堆设计模式实现(基于java.nio)
- 几种典型的服务器网络编程模型归纳( select poll epoll)
- epoll模型的EPOLLLT模式和EPOLLET模式比较
- epoll的反应堆实现模式
- epoll模型两种工作模式的思考
- 基于TCP连接的C S模式的最简单模型代码
- 【电子商务】浅谈网站盈利的几种模式
- Linux下基于EPOLL 模型,实现用户登录,客户端采用QT
- 浅谈 js中的几种模式 (一)
- 对linux 多路复用Epoll模型的水平出发模式和边缘触发模式的理解