ascs 简明开发教程(十):启动优化,对象池及对象恢复(服务端)

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

QQ交流群:198941541

如果你的socket的创建很耗时,你可以在服务器启动之前预先创建足够多的socket对象,定义宏ASCS_ASYNC_ACCEPT_NUM,或者重写virtual int server_base::async_accept_num()即可。比如你写个网游服务器,一台服务最多支持10000个玩家,可以让服务器在启动之前先预先创建10000个玩家,这样玩家登陆就会非常快,提高用户体验。

但有个问题你必须要知道,ascs在每接受一条连接之后,会马上再创建一个socket,以总是保持10000个异步accept请求,如果你不想要这个默认行为,还是拿上面的网游服务器举例,由于一台服务器最多只支持10000个玩家,上来一个玩家之后,只需要保持9999个异步accept请求即可,再上来一个玩家之后,只需要保持9998个异步accept请求即可,以此类推,于是你可以重写:

virtual void start_next_accept()
{
    if (server_base::size() >= 10000) //达到10000条连接之后,仍然保持一个异步accept请求,表示服务还在
        server_base::start_next_accept();
}

再看一个比较不常用的功能,如果我想只接受一条连接怎么办呢,可以如下(上面10000条连接上限的例子也可以这样做,彻底关闭监听):

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

既然都考虑到了启动优化问题,那再配合对象池,将可以更进一步的优化性能。对象池的开启只能通过定义宏ASCS_REUSE_OBJECT,开启之后,连接断开的顺序不变,仍然是 on_recv_error [on_msg_handle] on_close after_close(服务端一般不考虑after_close,那是给客户端重连用的),那么你在on_close里面释放资源的时候,就要考虑了,对于对象重用之后(已经变成了另外一个玩家了)仍然可用的资源,就不要释放了,否则对象池就白开了。然后还应该重写server_base::reset函数以便重置必要的内部状态(对象重用之前由object_pool调用,总之你要清楚,重用之后就是另外一个玩家了,你就知道重置哪些东西的,这些都是你的业务问题),最后一定记得调用server_base::reset函数,因为server_base也有许多内部状态需要重置。

关于对象恢复,还记得ascs 简明开发教程(四):多连接管理(服务端)里面说的连接管理吗?如果你也刚好用的是个整数标识客户端,那么你也可以不做连接管理而用ascs库的连接管理,客户端断线重连之后,服务器是没办法知道这次连接(对服务端来说永远是新连接)对应的前身是谁,需要客户端在重连之后,通过发送自定义消息给服务端(跟你的业务消息平级,所以ascs库是不认识这个消息的,需要你的打包解包器认识这个消息)报告连接断线之前的服务器端连接id,服务端收到这个消息的时候,以init = false调用server_base::restore_socket尝试恢复这条连接的id(你自己调用),注意我说的是尝试,因为不一定能恢复得了,只有在服务端socket结束了生命周期(即调用了after_close之后)之后,你才能将重连之后的socket恢复到之前的socket(id不变),如果恢复不了咋办呢?此时你可以通过发送自定义消息给客户端,让它等一下再尝试通知服务端恢复连接id,当然在恢复连接id之前,你的客户端应该被看成未连接状态,所有业务都不得开展,除了再次请求恢复连接id。注意如果你想要恢复的连接id已经被合法占用,就算找到已结束生命周期且id是你想要的id的socket,你也是不能成功恢复连接id的,这说明你有逻辑错误,id重复了。

那服务端初始连接id如何设定呢?此时你需要定义宏ASCS_START_OBJECT_ID为一个适当的值(或者调用object_pool::set_start_object_id,尽量早的调用它,服务端不可在service_pump::start_service之后调,客户端不可在multi_client_base::add_socket之后调),比如你的id范围是0~1000,那ASCS_START_OBJECT_ID应至少定义为1001,这样你才能给服务器端连接id定义初始值而不与还在请求异步accept的连接相冲突(因为这些连接在成功建立之后,会放到object_pool里面去,如果冲突了就会放不进而被直接踢下线),定义初始值也是通过发送自定义消息给服务端,服务端收到消息之后以init = true调用i_server::restore_socket接口(你自己调用),此时由你自己控制不同的客户端发送给服务端的连接id初始值互不相同,否则后面的连接id初始化会失败。

在调用i_server::restore_socket接口(特指恢复连接id而不是初始化连接id)之后且还未返回之前,如果恢复连接id成功,virtual void server_base::take_over(std::shared_ptr<server_socket_base> socket_ptr)会被调用(前面说了所有回调都在service线程里面,这个回调可以在也可以不在,所以没以on_开头,你在哪个线程调用restore_socket,它就在那个线程里面被回调),你重写它,把socket_ptr里面你自己的业务数据全部swap到本socket里面(注意可能需要互斥,由你的业务而定),所以你的业务数据最好是可swap的(简单数据类型和数组都不可swap),否则你就得深度复制数据,优化效果就打折扣了。

对象恢复功能只能通过宏ASCS_RESTORE_OBJECT开启,且与ASCS_REUSE_OBJECT互斥,即开启了对象恢复就不能开启对象重用,如果两者都定义,则对象恢复覆盖对象重用。当对象恢复开启时,在服务端你就不再需要释放任何资源了,reset也不会被回调,这是最高级别的优化了。

客户端也支持对象池,但不支持对象恢复(对象恢复是一个服务端概念),客户端对象池主要用于短连接,或者关闭了自动重连的长连接。

上一篇:ascs 简明开发教程(9)下一篇:ascs 简明开发教程(11)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值