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

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_HANDSHAKECORE_PINGCORE_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











分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics