C++高性能服務框架revolver:core結構與接口介紹

revolver的核心部件庫core是基於revolver base之上進行封裝的,實現TCP連接管理、消息隱射管理、服務登記和感知 、IFrame框架和插件等。以下是core的模塊結構圖:




1 Core Packet

CorePacket是core中統一定義的二進制協議類,描述如下:
class CCorePacket : public CBasePacket
{
public:

	void		set_data(CBasePacket& packet, bool zlib = true);
	void		get_data(CBasePacket& packet);
	...
protected:
	//編碼解碼函數
	virtual void	Pack(BinStream& strm) const;
	//解碼函數
	virtual void	UnPack(BinStream& strm);
	...
public:
	uint32_t	server_id_;		//服務器ID
	uint8_t		server_type_;	//服務器類型,0表示客戶端
	uint32_t	msg_id_;		//消息ID
	uint8_t		msg_type_;		//消息類型,例如獨立的PING PONG消息,握手消息,應用層消息等
	string		data_;			//消息內容
};

server_id_ 表示發送這個報文的服務ID,如果是客戶端就=0,
server_type_ 表示服務類型,具體的服務類型在core_server_type.h做定義
msg_id_ 表示本報文的協議ID,在DEF協議檔案中定義,只有當msg_type_ = CORE_REQUEST纔有效
msg_type_表示一個協議類型,是個枚舉:
typedef enum PacketClass
{
	CORE_HANDSHAKE,    //TCP握手協議類型
	CORE_REQUEST,      //TCP消息載體類型
	CORE_PING,         //TCP心跳協議類型
	CORE_MEDIA_SHELL,
	CORE_ZLIB,
	CORE_PONG
}PacketClass;
data_ 是協議體數據。消息消息是根據協議類型和消息ID來做協議觸發隱射的。

其中Pack接口是做二進制消息打包使用的,UnPack是二進制解包使用的。因爲CCorePakcet繼承了CBasePacket,這兩個接口是BasePacket的虛接口,主要是實現對<< 和>>流操作支持。
Pack的代碼實現:
void CCorePacket::Pack(BinStream& strm) const
{
        strm << server_id_ << server_type_ << msg_id_ << msg_type_ << data_;
}
UnPack的代碼實現:
void CCorePacket::UnPack(BinStream& strm)
{
        strm >> server_id_ >> server_type_ >> msg_id_ >> msg_type_ >> data_;
}
這連兩個函數主要是使用的Revolver Base中BinStream的<<和>>。具體細節可以查看對應的代碼。CorePacket打包成網絡字節序流代碼示例:
BinStream strm;
strm << packet; //packet爲CorePacket實例

2 Connection和連接管理

CConnection是一個TCP連接對象,負責TCP的連接發起、報文發送和接收、連接握手和校驗、連接維繫等工作。它是繼承了CEventHandle類,Reactor在觸發讀寫時間會直接調用對應的CConnection對象。以下是基本CConnection的接口描述:
class CConnection : public CEventHandler
{
public:
	...
	//事件接口
	int32_t			handle_input(BASE_HANDLER handle);
	int32_t			handle_output(BASE_HANDLER handle);
	int32_t			handle_close(BASE_HANDLER handle, ReactorMask close_mask);
	int32_t			handle_exception(BASE_HANDLER handle);
	int32_t			handle_timeout(const void *act, uint32_t timer_id);
	//發起一條TCP連接
	int32_t			connect(const Inet_Addr& remote_addr);
	int32_t			connect(const Inet_Addr& src_addr, const Inet_Addr& dst_addr);
	//關閉連接
	void			close();
	//發送數據
	int32_t			send(CCorePacket& packet, bool no_delay = false);
	int32_t			send(const string& bin_stream);
    ...

protected:
	...
	CSockStream		sock_stream_;		//SOCKET 對象實例
	SBuffer			sbuffer_;			//TCP發送BUFFER,解決報文發送分包問題
	RBuffer			rbuffer_;			//TCP接收BUFFER,解決報文粘包和組包問題
	BinStream		istrm_;				//接收的BinStream流對象
	uint8_t			server_type_;		//0表示客戶端
	uint32_t		server_id_;			//對端服務的server ID,如果是客戶端爲0
	Inet_Addr		remote_addr_;		//遠端地址
};
在CConnection實現中,會處理CORE_HANDSHAKE CORE_PING CORE_PONG類型的消息,其中CORE_HANDSHAKE會對遠端服務做身份校驗。CORE_PING和CORE_PONG是用來做連接心跳維繫的,一般是1分鐘發送一次,如果連接超過4個發送週期沒有到對端任何報文,就會斷開此連接。

連接管理器是實現對感知服務的CConnection的節點管理,連接管理器是將底層的TCP連接和地址 與 SERVER做一個相對關聯,上層向某個服務單元發送消息,直接將消息結構和SERVER ID傳遞給連接管理器,連接管理器就可以進行智發送。以下是幾個連接管理器定義的宏:
#define SendDispathByID(packet, id)\
	CONN_MANAGER()->send_dispatch_by_id(packet, id)

#define SendDispathByUDP(packet, id)\
	CONN_MANAGER()->send_dispatch_by_udp(packet, id)

#define SendUDP(packet, addr)\
	CONN_MANAGER()->send_udp(packet, addr)

#define SendTCP(packet, conn)\
	CONN_MANAGER()->send_tcp(packet, conn)
如果本地服務要像遠端服務(server_id  = 10)發送一個類型爲CCorePacket的hello_packet_ 消息:
SendDispathByID(hell_packet_, 10);
在這個函數裏面首先會檢查10這個服務單元節點是否存在,如果存在而且已連接,就直接調用其Connection進行發送,如果未進行連接,就會將報文放在一個緩衝隊列中,併發起TCP連接,這個時候是直接返回給上層。連接過程是異步的,如果連接完成,就會發送其緩衝隊列中的報文給對端服務單元。這樣做的目的是簡化上層業務和連接管理之間的耦合,降上層業務的複雜度。

3消息隱射


以上是整個revolver core的消息觸發和處理流程,其中消息體解析和ICmdTarget是消息隱射的主體模塊。其中ICmdTarget是消息隱射的虛接口,對上層業務需要處理的消息,通過繼承它就可以實現。一下是它接口定義:
class ICmdTarget
{
public:
	ICmdTarget();
	virtual ~ICmdTarget();

	//定義各種觸發參數,例如:SID,mssage class, connection句柄等等
	virtual int32_t on_event(uint32_t msg_id, uint32_t sid, CBasePacket* packet, CConnection* connection);
	//處理UDP消息
	virtual int32_t on_event(uint32_t msg_id, uint32_t sid, CBasePacket* packet, const Inet_Addr& remote_addr);

protected:
	virtual CTargetMessageManager* get_message_map() = 0;
};

typedef void (ICmdTarget::*TARGET_CALL)(void);
typedef map<uint32_t, CMD_MESSAGE_ENTRY>	CMD_MESSAGE_MAP;

消息隱射是採用類的成員函數進行隱射的,關於類成員函數指針的使用,請查看點擊打開鏈接,有詳細的介紹,我就不再介紹了。
如果要使用消息隱射,就需要在框架啓動的時候設置對應的消息分類和消息隱射器。以下是revolver例子工程裏相關的代碼處理:
	//設置消息處理器
	INIT_MSG_PROCESSOR1(&sample_server_);
	//設置要處理的消息羣體
	LOAD_MESSAGEMAP_DECL(SAMPLE_MSG);
其中INIT_MSG_PROCESSOR是設置消息處理器,LOAD_MESSAGEMAP_DECL是設置需要隱射的消息分類。

4 Daemon Client

Daemon Client是一個和精靈服務進行連接的處理模塊,主要是實現處理Daemond的消息和事件,在這裏值得一提的是,Daemon Client在連接Daemond的時候是採用daemon.revolver.com的域名連接,所以在運行服務單元的物理機器上需要配置daemon.revolver.com指向你的Daemond,關於Daemond的服務檢測和管理通告,我會在以後的BLOG中單獨介紹


5 ICoreFrame

ICoreFrame是整個core的對外核心接口,主要是負責實現框架的初始化、框架的銷燬、組件的即插即用、框架的啓動和停止以及操作系統的環境編程等。CoreFrame裏能即插即用的組件有以下幾個:
CDaemonClient DaemonClient組件
CCoreTCPListener TCP監聽服務組件
CoreUDPHandler UDP監聽服務組件
CCoreDCClient 數據層訪問組件(暫時不用)

ICoreFrame接口聲明:
class ICoreFrame
{
public:
	...
	void				init();
	void				destroy();
	void				start(bool wan = false);
	void				stop();
	//CORE庫的運行函數
	void				frame_run();
	//DAEMON CLIENT返回分配好的地址,進行網絡綁定,如果是DAEMON
	void				bind_port(uint16_t port);

	//組件設置
	void				create_udp();
	void				create_tcp_listener();
	void				create_daemon_client(IDaemonEvent* daemon_event, IDaemonConfig* config = NULL);
	void				create_dc_client();
	void				attach_server_notify(ICoreServerNotify* notify);
	//提供給上層的事件
	virtual void		on_init() = 0;
	virtual void		on_destroy() = 0;

	virtual void		on_start() = 0;
	virtual void		on_stop() = 0;
protected:
	CDaemonClient*		daemon_client_;		//DAEMON CLIENT組件
	CCoreTCPListener*	listener_;			//TCP監聽服務組件
	CoreUDPHandler*		udp_handler_;		//UDP服務組件
	CCoreDCClient*		dc_client_;			//DC數據庫訪問組件
};

一般服務如果基於CORE來編寫,就可以通過實現on_init, on_destory, on_start, on_stop來實現服務功能,具體的可以參考revolver 項目sample_server中的sample_frame.cpp











發佈了39 篇原創文章 · 獲贊 76 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章