ascs demo解释(二):echo_client + echo_server

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

QQ交流群:198941541

echo_client + echo_server用于性能测试,同时echo_server还多开了两个端口用于服务demo client,这个在前一篇教程里面已经说过了。

先说说echo_client,它演示了 关闭对象生命同期跟踪(宏ASCS_DELAY_CLOSE),同步批量派发消息(宏ASCS_SYNC_DISPATCH,此时你在on_msg里面处理消息),异步批量派发消息(宏ASCS_DISPATCH_BATCH_MSG,此时和单条派发消息一样,也是在on_msg_handle里面处理消息,只是两个on_msg_handle签名有所不同),运行时增减service线程(宏ASCS_DECREASE_THREAD_AT_RUNTIME)等,其它的宏已经在上一篇里面解释过了。

关于对象生命同期管理,在 ascs 简明开发教程 里面已经详细说过了,这里不再鳌述。

关于批量派发消息,总效率肯定高于单条派发,但带来一个小问题,在每一条连接上统计速度的话,会出现锯齿状,就是说在发送端以稳定速度发送的情况下,接收端处理的速度仍然显得不平滑,时高时低(虽然平均速度不变甚至稍高),原因是在on_msg或者on_msg_handle里面派发了过多的消息,阻塞了service线程,解决办法就是像echo_server一样,虽然ascs派发了许多消息,但一次只处理10条,这样在总效率和处理平滑性上可以得到一定的平衡。但这种方法不能用于同步批量派发消息(除非你的消息没有相关性,可以乱序),因为在on_msg里面,如果你不处理完所有消息,剩下的消息会进行异步派发(是否批量根据宏的定义决定),那么这些异步派发的消息,和新收到的做同步批量派发的消息,将得不到顺序上的保证,就会乱序。

关于运行时增减service线程(通过service_pump的add_service_thread和del_service_thread接口实现),ascs库将循环调用io_conext的run_one而不是原来的run,每处理完一个异步回调,就要再发起一次run_one,所以效率上会稍有影响。另外,当减少service线程时,有可能不会马上减少,因为run_one是阻塞的,要解除阻塞必须来一个异步事件,如果一直没有异步事件发生,service线程也是减不下来的。解决这个问题可以改为调用带超时的run_one,但我觉得并没有多大的必要,大家了解一下即可。

echo_client运行参数可以通过传入-h来显示出来,支持指定service线程数(默认1),消息发送线程数(默认8), 和连接数(默认16),service线程数和连接数都可以在进程运行起来之后再修改,前者通过输入increase thread和decrease thread,后者通过输入+n和-n。

echo_client运行起来之后,输入命令开始性能测试,命令格式是 “发送消息数量 消息长度 消息内容 模式 循环次数”,比如 10000 1024 0 0 5,具体解释为:发送10000条消息;每条消息1024字节;消息内容填充字符\0(但前面有sizeof(size_t)个字节里面有发送消息的序号,以验证消息的合法性,至少验证了消息是否乱序);模式为0,即每条连接上都发送10000条消息,总共16 * 10000条消息,如果模式为1,则每个消息都只随机选择一条连接来发送,总共10000条消息;循环测试5次。

另外演示了使用几乎所有打包解包器,你可以对比它们的性能差异,通过宏PACKER_UNPACKER_TYPE切换它们。

其它演示了一下比如列出所有连接(list_all_object),列出所有连接的状态(list_all_status),统计(get_statistic)等。

 

echo_server演示了与echo_client几乎相同的功能,但它没有开启同步批量派发消息,因为它没有在批量派发时处理完所有消息,如下:

	virtual size_t on_msg(std::list<out_msg_type>& msg_can)
	{
		if (!is_send_buffer_available())
			return 0;

		ascs::do_something_to_all(msg_can, [this](out_msg_type& msg) {this->send_msg(std::move(msg), true);});
		msg_can.clear();

		return 1;
	}

你可能会问,我把第四五行代码注掉,不就处理了所有消息了吗?但请注意第六行代码,我们以can_overflow为true调用了send_msg,这意味着肯定会成功且缓存占用不可控,如果echo_client发得快,但接收得慢,那echo_server的发送缓存会变得越来越大且不受控制,它将最终因为内存耗尽而崩溃,或者因为占用过多内存而被OOM Killer杀掉。那我们以can_overflow为false调用send_msg不就行了?答案是行是行,那如何处理send_msg失败呢?自旋等待(sync_send_msg)就会阻塞service线程,这将是会带来死锁的,如果把消息缓存在另外的地方,则那个地方仍然会满,这样下去就没完没了了,所以在我看来echo_server这种业务,就不能开启同步批量派发消息。那为什么echo_client可以呢?答案是因为echo_client在处理消息时(验证一下消息的顺序性,并记录一下收到的总字节数)没有阻塞的可能。另外它还演示了:

在echo_socket里面调用echo_server,方法是从i_server继承得到i_echo_server ,并在里面增加了一个接口virtual void test() = 0;,echo_socket通过get_server().test();调用这个接口,echo_server实现这个接口,这样echo_socket就可以与echo_server交互了。

normal_socket的对端是demo client,它演示了不用宏开启心跳功能(因为demo client里面开启了心跳功能):virtual void on_connect() {start_heartbeat(5);},注意心跳间隔需要跟对方保持一次,这里是5秒一次。

normal_server即demo client所连接的服务器,它演示了只接收一条连接:

    virtual int async_accept_num() {return 1;}
    virtual bool on_accept(object_ctype& socket_ptr) {stop_listen(); return true;}

所以如果与demo client的连接意外中断,那么它将再也无法重连到服务器(虽然它开启了自动重连),这是因为normal_server在接收到一条连接之后就停止监听了(stop_listen),这并不ascs有问题,而是我故意为之。

short_connection演示了主动断开连接,即调用force_shutdown函数。

最后在main函数里面演示了service_pump和single_service_pump在使用上的差异。

上一篇:ascs demo解释(一):client

下一篇:ascs demo解释(三):concurrent_client + concurrent_server

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值