游戏服务器之主动连接线程池

发布时间:2017-1-17 14:53:44 编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"游戏服务器之主动连接线程池",主要涉及到游戏服务器之主动连接线程池方面的内容,对于游戏服务器之主动连接线程池感兴趣的同学可以参考一下。

本文内容是游戏服务器之主动连接线程池,功能是实现处理服务器之间主动发起的连接的网络的数据收发。 一般来说,在场景服务器里连接其他服务器进程的连接是启动了新的线程的(如 场景服务器的主动连接:db服务器、社会服务器、日志服务器)。 但是也有不启动线程的客户端连接的做法。对于这类方式,他们的网络收发是统一由主动连接线程池来处理。 目前使用案例: 例如游戏服务器的网关服务器的主动连接:社会服务器、db服务器、所有场景服务器。 本文内容: 1、线程类型 (1)连接测试线程 (2)验证线程 (3)网络处理线程 2、连接池初始化 3、创建连接到连接池 4、主动连接会话结构 1、线程类型 客户端连接池有3类:连接测试线程、验证线程、网络收发处理线程。 (1)连接测试线程 connection_thread_manager<check_connect_thread> checkconnectThread 连接测试线程是来处理主动连接是否能连接成功,如果成功就转到验证线程来处理,如果失败就一直连接(几秒的间隔)。 (2)验证线程 connection_thread_manager<check_wait_thread> checkwaitThread 在构造函数里创建epoll描述符, 在例程里处理转过来的连接任务列表,处理该TCP连接的验证,如果验证不通过,需要回收这个连接。 验证方式是处理该连接的epoll事件看有没有错误,处理连接自定义的checkRebound ,这个根据需求,是否需要检查该连接的合法性。   如:中心服务器主动连接到登录服务器(使用主动连接线程池),需要在登录服务器创建会话对象后,在同步线程中返回消息给中心服务器后,中心服务器验证线程的对该主动连接的验证工作才算成功通过。 void check_wait_thread::run() { ... if (!tasks.empty()) { int retcode = epoll_wait(kdpfd, &epfds[0], task_count, 0); if (retcode > 0) { for(int i = 0; i < retcode; i++) { tcp_client *task = (tcp_client *)epfds[i].data.ptr; if (epfds[i].events & (EPOLLERR | EPOLLPRI)) { //套接口出现错误 remove(task); task->resetState(); } else if (epfds[i].events & EPOLLIN) { switch(task->checkRebound())//验证连接 { case 1: //验证成功,获取下一个状态 remove(task); if (!pool->addMain(task)) task->resetState(); break; case 0: //超时,下面会处理 break; case -1: //验证失败,回收任务 remove(task); task->resetState(); break; } } } } } ... } (3)网络处理线程 connection_thread_manager<main_client_thread> clienttaskThread 处理网络的实际数据的收发。 详细参考:http://blog.csdn.net/chenjiayi_yun/article/details/31765803 内容大致是相同的。 只是那里是被动连接的数据收发处理为例,这里是主动连接的数据收发处理。 2、连接池初始化 初始化线程池中的各类线程的数量 bool tcp_client_pool::init(const uint32 perThreadSize) { //测试线程数量1个 if (!checkconnectThread.init(1, 1, "checkconnectThread",this)) { return false; } //验证线程数量1个 if (!checkwaitThread.init(1, 1, "checkwaitThread",this)) { return false; } main_client_thread::settMaxSize(perThreadSize); int maxThreadCount = (maxConns + main_client_thread::getMaxSize() -1)/main_client_thread::getMaxSize(); //网络处理线程数量跟连接最大限制有关 if (!clienttaskThread.init(1, maxThreadCount, "clienttaskThread",this)) { return false; } return true; } 3、创建连接到连接池 例如创建主动到数据库的连接,并添加到线程池。 网关跟档案服务器的连接 。  dbClient = new db_client("Record", serverEntry->pstrExtIP, serverEntry->wdExtPort,serverEntry->ServerID); if(!dbClient || !clientPool->put(dbClient)) { g_log->error("没有足够内存,不能建立db 服务器客户端实例"); return false; } 线程池会把连接加入到连接线程,等到线程池启动后,连接测试线程会处理这些主动连接的连接测试, 连接失败会一直连接,连接成功后会验证连接,验证成功后就转到网络处理线程(网络处理线程可能有多个,选择其中一个来处理)。 bool tcp_client_pool::put(tcp_client *task) { check_connect_thread *pThread = checkconnectThread.getOne(); if (pThread) { pThread->_add(task); } else { g_log->fatal("%s: 不能得到一个空闲线程", __PRETTY_FUNCTION__); } return true; } 其中: class db_client : public client_no_msg_queue ,没有使用消息队列,那么消息的处理就会在线程clienttaskThread(网络数据处理线程)里处理了 4、主动连接会话结构 客户端连接tcp_client包含的内容含: 连接任务类型 uint32 taskType; 底层套接口  tcp_socket *pSocket; 连接状态volatile ConnState state; 是否含有读事件 bool fdsradd; 是否支持压缩 const bool compress; 服务器地址 const std::string ip; 服务器端口 const unsigned short port; 使用套接口收发。 ...

上一篇:
下一篇:安卓开发经典实例收藏

相关文章

相关评论