Reactor模式是网络编程中常用的模式,著名的libevent网络库就是采用了Reactor模式。最近通过阅读Douglas C. Schmidt 1995年写的关于Reactor模式的论文,理解了Reactor模式,下面是我通过阅读论文的感悟和复现论文中日志服务器的例子程序源码。
该论文讲解透彻,点此下载,建议阅读
Reactor模式常用于同步IO模型,本文中以select()为例进行介绍。
Reactor类图如上所示,有以下几个部分构成
Handles(句柄):唯一表示系统管理资源。例如文件描述符(file descriptor, fd)。
Synchronous Event Demultiplexer(同步事件复用器):阻塞等待一组Handle上event发生,例如select(),poll()等。
Initiation Dispatcher(分发器):定义注册(registering)事件回调对象(Event Handlers),移除(removing)事件回调对象(Event Handlers)和分发(dispatch) 事件。Demultiplexer负责等待事件发生,当时间发生后,Demultiplexer通知Dispatcher回调具体的Event Handlers。
Event Handler(事件回调抽象类):事件回调的接口。
Concrete Event Handler(具体事件回调类):事件回调的具体处理逻辑。在分布式日志服务器中有两个Concrete Event Handler:分别是Logging Handler 和 Logging Acceptor,Logging Handler负责接受和处理日志,Logging Acceptor负责接受连接并创建Logging Handler。
Reactor模式的优点:
(1) 业务处理逻辑和复用器(Demultiplex)、调度器(dispatch)分离。
(2) 提高了事件驱动(event-driven)应用程序的模块化,复用性。
(3) 通过了粗粒度的并发控制。Reactor模式中同一个dispatcher串行(serialize)调用事件回调对象,这样避免了复杂的同步控制。
Reactor模式的缺点:
(1) 非抢占式(Non-preemptive) Event Handlers中不能产生长时间阻塞,这样会阻塞其他Handles。
Reactor论文链接 >https://www.cse.wustl.edu/~schmidt/PDF/reactor-siemens.pdf
代码实现了分布式日志服务器,有以下几个类构成。
Initiation_Dispatcher类是分发器。
Event_Handler类是事件回调的抽象接口。
Logging_Acceptor类负责接受连接并创建Logging Handler对象。
Logging_Handler类复杂负责接受日志并输出到标准输出。
Initiation_Dispatcher.h
#ifndef INITIATION_DIAPATCH_HH
#define INITIATION_DIAPATCH_HH
#include
#include
#include
#include
#include
#include
#include
#include
#include "SingletonTemplate.h"
#include "Event_Handler.h"
using namespace std;
class Initiation_Dispatcher
{
public:
int register_handler(Event_Handler *eh, Event_Type et);
int remove_handler(Event_Handler *eh, Event_Type et);
int handler_events(time_t *timeout = 0);
private:
int maxfdpl;
fd_set readset;
unordered_map<int, Event_Handler*> ReadHandleMap;
unordered_map<int, Event_Handler*> AcceptHandleMap;
};
#endif
Initiation_Dispatcher.cpp
#include "Initiation_Dispatcher.h"
int Initiation_Dispatcher::register_handler(Event_Handler *eh, Event_Type et)
{
if (et == ACCEPT_EVENT)
{
AcceptHandleMap.insert(make_pair(eh->get_handle(), eh));
}
else if (et == READ_EVENT)
{
ReadHandleMap.insert(make_pair(eh->get_handle(), eh));
}
}
int Initiation_Dispatcher::remove_handler(Event_Handler *eh, Event_Type et)
{
if (et == ACCEPT_EVENT)
{
AcceptHandleMap.erase(eh->get_handle());
}
else if (et == READ_EVENT)
{
ReadHandleMap.erase(eh->get_handle());
}
}
int Initiation_Dispatcher::handler_events(time_t *timeout)
{
// 清除标志位
FD_ZERO(&readset);
maxfdpl = -1;
unordered_map<int, Event_Handler *>::iterator iter;
for (iter = AcceptHandleMap.begin(); iter != AcceptHandleMap.end(); ++iter)
{
FD_SET(iter->first, &readset);
if(maxfdpl < iter->first)
{
maxfdpl = iter->first;
}
}
for (iter = ReadHandleMap.begin(); iter != ReadHandleMap.end(); ++iter)
{
FD_SET(iter->first, &readset);
if(maxfdpl < iter->first)
{
maxfdpl = iter->first;
}
}
maxfdpl += 1;
select(maxfdpl, &readset, NULL, NULL, NULL);
for (iter = AcceptHandleMap.begin(); iter != AcceptHandleMap.end(); ++iter)
{
if(FD_ISSET(iter->first, &readset))
{
iter->second->handle_event(ACCEPT_EVENT);
}
}
for (iter = ReadHandleMap.begin(); iter != ReadHandleMap.end(); ++iter)
{
if(FD_ISSET(iter->first, &readset))
{
iter->second->handle_event(READ_EVENT);
}
}
}
Event_Handler.h
#ifndef EVENT_HANDLE__HH
#define EVENT_HANDLE__HH
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
enum Event_Type
{
ACCEPT_EVENT = 01,
READ_EVENT = 02
};
class SOCK_Stream
{
public:
int& get_handle()
{
return fd;
}
int recv(char * buff, int length)
{
int bytes_read = read(fd, buff, length);
return bytes_read;
}
void Close()
{
close(fd);
}
private:
int fd;
};
class Event_Handler
{
public:
virtual int handle_event(Event_Type et) = 0;
virtual int get_handle(void) = 0;
};
class SOCK_Acceptor
{
public:
SOCK_Acceptor(short &port)
{
listenfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(port);
bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
listen(listenfd, 10);
}
int Accept(SOCK_Stream &new_connection)
{
//int accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len);
// 有新的连接,处理
socklen_t len = sizeof(cliaddr);
connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &len);
new_connection.get_handle() = connfd;
cout << "Accept Client success" << endl;
return new_connection.get_handle();
}
int get_handle()
{
return listenfd;
}
private:
int listenfd, connfd;
struct sockaddr_in servaddr, cliaddr;
};
#endif
Logging_Acceptor.h
#ifndef LOGGING_ACCEPTOR_HH
#define LOGGING_ACCEPTOR_HH
#include "Event_Handler.h"
#include "SingletonTemplate.h"
class Logging_Acceptor : public Event_Handler
{
public:
Logging_Acceptor(short &port);
virtual int handle_event(Event_Type et);
virtual int get_handle(void)
{
return acceptorObj.get_handle();
}
private:
SOCK_Acceptor acceptorObj;
};
#endif
Logging_Acceptor.cpp
#include "Logging_Acceptor.h"
#include "Initiation_Dispatcher.h"
#include "Logging_Handler.h"
Logging_Acceptor::Logging_Acceptor(short &port) : acceptorObj(port)
{
singleton::instance().register_handler(this, ACCEPT_EVENT); // 向 Initiation Dispatcher 注册
}
int Logging_Acceptor::handle_event(Event_Type et)
{
// Can only be called for an ACCEPT event.
assert(et == ACCEPT_EVENT);
SOCK_Stream new_connection;
acceptorObj.Accept(new_connection);
Logging_Handler *handler = new Logging_Handler(new_connection);
}
Logging_Handler.h
#ifndef LOGGING_HANDLER_HH
#define LOGGING_HANDLER_HH
#include "Event_Handler.h"
#include "Initiation_Dispatcher.h"
#define MAXLINE 1000
// the logging handler class
class Logging_Handler : public Event_Handler
{
public:
Logging_Handler(SOCK_Stream &cs);
virtual int handle_event(Event_Type et);
virtual int get_handle(void)
{
return peer_stream_.get_handle();
}
private:
SOCK_Stream peer_stream_;
char buff[MAXLINE];
};
#endif
Logging_Handler.cpp
#include "Logging_Handler.h"
#include "SingletonTemplate.h"
Logging_Handler::Logging_Handler(SOCK_Stream &cs)
: peer_stream_(cs)
{
// Register with the dispatcher for
// READ events.
singleton::instance().register_handler(this, READ_EVENT);
}
int Logging_Handler::handle_event(Event_Type et)
{
if (et == READ_EVENT)
{
int bytes_recv = peer_stream_.recv(buff, sizeof(buff));
if (bytes_recv == 0)
{
// 表示socket关闭
cout << "fd = " << peer_stream_.get_handle() << "Closed." << endl;
peer_stream_.Close();
singleton::instance().remove_handler(this, READ_EVENT);
delete this;
}
else if(bytes_recv > 0)
{
// 将接受到的日志标准输出
cout << peer_stream_.get_handle() << "Log:" << buff << endl;
// 清空 buff
bzero(buff, sizeof(buff));
}
}
}
SingletonTemplate.h
#pragma once
template <typename T>
struct singleton {
private:
struct object_creator {
object_creator() {
singleton::instance();
} // 初始化create_object时,初始化singleton
inline void do_nothing() const {
}
};
static object_creator create_object;
singleton();
public:
typedef T object_type;
static object_type &instance() {
static object_type obj;
create_object.do_nothing(); // 使用create_object,使得编译器一定会初始化create_object
return obj;
}
};
template <typename T>
typename singleton::object_creator singleton::create_object;
main.cpp
#include "Initiation_Dispatcher.h"
#include "Logging_Acceptor.h"
int main()
{
short port = 8888;
Logging_Acceptor AcceptorObj(port);
for(;;)
{
singleton::instance().handler_events();
}
return 0;
}