`
hulianwang2014
  • 浏览: 692004 次
文章分类
社区版块
存档分类
最新评论
  • bcworld: 排版成这样,一点看的欲望都没有了
    jfinal

C++高性能服务框架revolver:base结构分析

 
阅读更多

revolver基础库的结构图如下:


主要是三部分:reactor模块、关联组件模块、独立组件。

1.reactor

reactor模块主要是实现网络的分时复用设计的模块,可以在同一个线程模式下处理来自网络的读写事件、内部消息事件、定时器事件。以下是reactor的接口定义:
class CReactor
{
public:
       ....
	void	set_message_processor(IMessageProcessor* proc){msg_proc_ = proc;};

	virtual int32_t open_reactor(uint32_t number_of_handlers) = 0;
	virtual int32_t close_reactor() = 0;

	virtual int32_t event_loop() = 0;
	virtual int32_t stop_event_loop() = 0;

	//事件操作
	//添加一个事件的监听
	virtual int32_t register_handler(CEventHandler *handler, uint32_t masks) = 0;
	//删除一个事件的特定监听
	virtual int32_t remove_handler(CEventHandler *handler, uint32_t masks) = 0;
	//删除一个事件
	virtual int32_t delete_handler(CEventHandler *handler, bool del_event_obj = false) = 0;
	//定时器操作 
	//添加一个定时器
	virtual uint32_t set_timer(CEventHandler *event_handler, const void *act, uint32_t delay) = 0;
	//删除一个定时器
	virtual uint32_t cancel_timer(uint32_t timer_id, const void **act) = 0;

protected:
	IMessageProcessor* msg_proc_;
};
其中msg_proc_是内部消息队列处理器。

reactor的核心函数是event_loop,event_loop是事件轮询函数,所有的分时复用在其中实现,流程伪代码为:
void event_loop()
{
		....
		//添加被监控的时间
		add_event_to_select(...);

		//设置SELECT堵塞时间
		struct timeval timeout;
		timeout.tv_sec = 0;
		timeout.tv_usec = select_delay_ * 1000;
		
		//进行SOCKET集合的事件扫描
		int32_t count = ::select(max_fd, &read_set, &write_set, &expeption_set, &timeout);
		if(count > 0) {
			//进行SOCKET的事件处理
		}

		//扫描定时器
		select_delay_ = timer_queue_.expire();
		
		//扫描内部消息队列
		if(msg_proc_ != NULL){
			msg_proc_->processor();
		}
		...
}
event_loop最主要的工作就是扫描事件。

1.1 EventHandler

CEventHandler是处理reactor触发的事件的,当有事件到来,loop_event会找到对应的event handler进行触发,CEventHandler的事件分类枚举:
typedef enum EVENT_MASK
{
	MASK_READ      = (1 << 0),//读事件
	MASK_WRITE     = (1 << 1),//写事件
	MASK_TIMEOUT   = (1 << 2),//超时事件
	MASK_EXCEPT    = (1 << 3),//异常事件
}EVENT_MASK;
事件判断值采用2进制进位来表示,1个event_value是否是否是读事件
	if(event_value & MASK_READ)
	{
             //进行读事件处理
	}
CEventHandler类接口一般只需要继承实现以下几个接口:
public:
	virtual int32_t			handle_timeout(const void *act, uint32_t timer_id);//超时事件
	virtual int32_t			handle_input(BASE_HANDLER handle);//socket读事件
	virtual int32_t			handle_output(BASE_HANDLER handle);//socket写事件
	virtual int32_t			handle_close(BASE_HANDLER handle, ReactorMask close_mask);//socket关闭
	virtual int32_t			handle_exception(BASE_HANDLER handle);//socket异常
以上几个接口根据需要进行实现,例如:只需要实现一个定时器,只需要实现handle_timeout接口。

1.2 queue

revolver的消息队列实现其实很简单,通过一个继承IMessageProcessor并设置到reactor当中进行消息监听。IMessageProcessor是个即插即用的接口。revolver的消息队列定义如下:

template<class T, int32_t CAPACITY>
class BaseQueue_T
{
public:
	BaseQueue_T()
	{
		data_ = new T[CAPACITY];
		rindex_ = 0;
		windex_ = 0;
	};

	~BaseQueue_T()
	{
		delete []data_;
	};

	bool put(const T& element)
	{
		//像队列中PUT一个消息
		return true;
	};

	bool get(T& element)
	{	
		//从队列中get一下消息
		return true;
	};

private:
	T*					data_;
	volatile int32_t	rindex_;
	volatile int32_t	windex_;
}
其中rindex_是队列读取位置,windex_是队列写入位置。T表示的是所用的消息类型。


1.3 Socket


以上SOCKET模块的继承和调用关系,BaseSocket是SOCKET的基础封装,主要是实现些send recv等函数,SocketDgram是UDP Socket的实现,SocketStream是TCP Socket的实现。SocketConnector是TCP连接器,CSocketAcceptor是TCP接收器。具体的可以看对应的代码。值得一提的是windows下的UDP Socket的ICMP处理问题,在UDP Socket在在open函数中有下面一段代码:
#ifdef WIN32 //解决WINSOCK2 的UDP端口ICMP的问题
	int32_t byte_retruned = 0;
	bool new_be = false;  

	int32_t status = WSAIoctl(handler_, SIO_UDP_CONNRESET,  
		&new_be, sizeof(new_be), NULL, 0, (LPDWORD)&byte_retruned, NULL, NULL);  
#endif
这段代码是为了解决WINDOWS下reactor接收不到ICMP信号的问题。

1.4定时器

revolver的定时器是个相对较复杂的模块,以后打算用专门的篇幅来介绍。

备注:WINDOWS下的revolver只能用来做调试和测试作用,不可以用来做单独的服务。可以用来做客户端的网络模型。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics