ascs 简明开发教程(十三):发送接收消息类型

31 篇文章 0 订阅
31 篇文章 1 订阅

QQ交流群:198941541

发送消息类型由打包器决定,打包器都继承自 template<typename MsgType> class i_packer,继承之后,你将自动得到如下定义:

template<typename MsgType>
class i_packer
{
public:
	typedef MsgType msg_type;
	typedef const msg_type msg_ctype;
	typedef list<msg_type> container_type;
};

注意这里的container_type并不是ascs需要的容器,而是i_packer接口里面需要的容器(打包器输出值)。那么打包器返回一个容器有什么意义呢?这其实是一种内存优化,比如你的数据已经存放在msg_type类型里面了,那么打包的时候,直接把包头打在另一个msg_type里面,加上你的数据通过链表返回,这样就避免了重新分配内存和拷贝内存,这是流式socket的好处,UDP就不行了,但好在UDP无需包头。

显然的,不是任意类都可以做为发送消息类型,它必须要提供如下接口:

bool empty() const
size_t size() const
const char* data() const

注意ascs只支持按对象访问发送消息,不支持对象指针、简单数据指针和数组。对于对象指针(必须是动态分配的),你可以用unique_buffer或者shared_buffer来包装它(在packer里面包装),它会把->操作转换成.操作(跟std::string类似),让ascs觉得它是在访问对象而不是对象指针;对于简单数据指针和数组(必须是动态分配的),你可以直接用ascs::ext::basic_buffer或者仿照它自己实现一个类似的。

ascs通过打包器得到消息(your_packer::msg_type类型或者list<your_packer::msg_type>类型)之后,会swap到in_msg对象里面(不会有拷贝,除非你用了自己写的消息类型,且用拷贝实现了swap,这是违背标准的,除非对于非常少量的数据,你做了优化,比如在栈上存储,高版本VC++里面的std::string采用了类似优化),in_msg的定义如下(其中InMsgType是个模板参数,等于your_packer::msg_type):

#ifdef ASCS_SYNC_SEND
	typedef obj_with_begin_time_promise<InMsgType> in_msg;
#else
	typedef obj_with_begin_time<InMsgType> in_msg;
#endif

你无需了解obj_with_begin_time_promise或者obj_with_begin_time的详细功能(它其实就是把消息打上时间戳用于性能统计),因为它们继承自your_packer::msg_type,你直接把它们当成your_packer::msg_type类型使用即可。而且ascs会尽量不让你感知到in_msg的存在,所以在on_msg_send里面传入的参数仍然是your_packer::msg_type类型,但是如果定义了宏ASCS_WANT_BATCH_MSG_SEND_NOTIFY,on_msg_send里面传入的参数将会是一个容器(这个容器是上一篇里面说的容器,不是i_packer接口里面用的容器),此时你需要知道,容器里面其实是in_msg类型,但你可以当成your_packer::msg_type类型使用。

 

接收消息类型由解包器决定,解包器都继承自 template<typename MsgType> class i_unpacker,继承之后,你将自动得到如下定义:

template<typename MsgType>
class i_unpacker
{
public:
	typedef MsgType msg_type;
	typedef const msg_type msg_ctype;
	typedef list<msg_type> container_type;
};

注意这里的container_type并不是ascs需要的容器,而是i_unpacker接口里面需要的容器(解包器输出值)。那么解包器返回一个容器有什么意义呢?这主要是考虑到粘包的问题,这是流式socket必须要面对且解决的问题,UDP每次读取都是一个且只有一个完整的消息,所以理论上就不需要容器了,但为了统一,仍然使用了i_unpacker接口,所以仍然以容器的方式返回消息。

显然的,不是任意类都可以做为接收消息类型,它必须要提供如下接口(如果你不处理消息的话):

size_t size() const
const char* data() const

且当数据为空时,data() 仍能返回有效指针(跟std::string类似),这是因为ascs在处理接收消息时,没有判断过数据是否为空而是直接打印 data() 内容。但由于你肯定要重写消息处理函数自己处理消息,所以ascs的消息处理函数是调用不到的,那么接收消息对象的 data() 函数的行为就完全由你的消息处理函数决定了。如果接收消息是对象指针(必须是动态分配的),你同样需要用unique_buffer或者shared_buffer来包装它(在unpacker里面包装),因为ascs只支持按对象访问接收消息(跟发送消息一样);对于简单数据指针和数组(必须是动态分配的),你可以直接用ascs::ext::basic_buffer或者仿照它自己实现一个类似的。

ascs通过解包器得到消息(list<your_unpacker::msg_type>类型)之后,会swap到out_msg对象里面,out_msg的定义如下(其中OutMsgType是个模板参数,等于your_unpacker::msg_type):

typedef obj_with_begin_time<OutMsgType> out_msg;

你无需了解obj_with_begin_time的详细功能(它其实就是把消息打上时间戳用于性能统计),因为它继承自your_unpacker::msg_type,你直接把它当成your_unpacker::msg_type类型使用即可。而且ascs会尽量不让你感知到out_msg的存在,所以在on_msg_handle里面传入的参数仍然是your_unpacker::msg_type类型,但是如果定义了宏ASCS_DISPATCH_BATCH_MSG,on_msg_handle里面传入的参数将会是一个容器(这个容器是上一篇里面说的容器,不是i_unpacker接口里面用的容器),此时你需要知道,容器里面其实是out_msg类型,但你可以当成your_unpacker::msg_type类型使用。

注意如果定义了宏ASCS_SYNC_DISPATCH,on_msg里面的容器类型是list<your_unpacker::msg_type>或者list<udp_msg<your_unpacker::msg_type>>,与ascs用的容器没有关系。

 

那么重写时,到底怎么写才能通用呢(怎么换打包解包器都能用,TCP和UDP也能通用),可以参考如下(如果你的类也是模板类,可能需要在参数前面加上 typename 关键字,这是c++标准之规定):

#ifdef ASCS_WANT_MSG_SEND_NOTIFY
	virtual void on_msg_send(in_msg_type& msg)
#elif defined(ASCS_WANT_BATCH_MSG_SEND_NOTIFY)
	virtual void on_msg_send(in_container_type& msg_can)
#endif

#ifdef ASCS_WANT_ALL_MSG_SEND_NOTIFY
	virtual void on_all_msg_send(in_msg_type& msg)
#endif

#ifdef ASCS_SYNC_DISPATCH
	virtual size_t on_msg(std::list<out_msg_type>& msg_can)
#endif

#ifdef ASCS_DISPATCH_BATCH_MSG
	virtual size_t on_msg_handle(out_queue_type& msg_can)
#else
	virtual bool on_msg_handle(out_msg_type& msg)
#endif

其中in_msg_type和out_msg_type是ascs::tcp::socket_base对your_packer::msg_type和your_unpacker::msg_type的typedef。on_all_msg_send传出in_container_type而不是in_queue_type是因为它无需考虑线程安全。注意UDP稍有区别,因为UDP消息需要记录对方地址,所以它们是ascs::udp::udp_msg<your_packer::msg_type>和ascs::udp::udp_msg<your_unpacker::msg_type>的typedef。

上一篇:ascs 简明开发教程(12)下一篇:ascs 简明开发教程(14)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值