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只能用來做調試和測試作用,不可以用來做單獨的服務。可以用來做客戶端的網絡模型。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章