天天对着不一样的计划,多多少少有一种无形的压力。特别是对技术很差的我来讲,过程当中遇到的问题实在很多,时常纠结良久。时间慢慢流逝,最后虽然感受有些不足,可是也不至于差强人意。商业版的PF核心已经升级到1.0.5版本,增添和完善了许多功能。核心主要完善了网络模块、脚本模块、文件模块、引擎模块、缓存模块等等,并制做了基本的场景插件和AI插件。将来的PF将支持更多的功能,将安装和使用更加的自动化,执行一个脚本就能完成许多没必要要的步骤。因此将来的脚本工具是一个必须完成的功能,在此咱们将迎来一个个热爱开源项目的同仁和期待大家的加入。5月商业版服务器的开发总结,将全面将制做原理和遇到的麻烦分享,但愿你们可以一块儿进步。原理比如是渔网和捕鱼的技术,虽然没有源代码,我想比源代码来的更加有价值。若是你们愿意,能够加入咱们的群共同讨论。html
每日都在计划表中纠结,一步步辛酸,一步步艰难的前行。linux
部分商业核心代码,暂时不予开源。git
#include "pf/base/string.h" #include "pf/base/log.h" #include "pf/base/time_manager.h" #include "pf/net/packet/factorymanager.h" #include "pf/sys/thread.h" #include "common/define/enum.h" #include "common/define/macros.h" #include "common/define/net/packet/id/clientlogin.h" #include "common/define/net/packet/id/billinglogin.h" #include "common/define/net/packet/id/logincenter.h" #include "common/net/packet/client_tologin/ask_login.h" #include "common/net/packet/login_toclient/ask_login.h" #include "common/net/packet/login_tocenter/role_kick.h" #include "common/net/packet/login_tobilling/auth.h" #include "common/net/packet/billing_tologin/auth.h" #include "common/net/packet/login_toclient/turn_status.h" #include "connection/login.h" #include "engine/system.h" #include "connection/queue/turn.h" #include "logic/login/controllers/account.h" using namespace logic::login; using namespace common::define::net::packet; AccountController::AccountController() { core_ = NULL; } AccountController::~AccountController() { //do nothing } bool AccountController::setuplayout() { return true; } int32_t AccountController::request(uint8_t type, void *data) { __ENTER_FUNCTION int32_t result = -1; switch (type) { case kLogicRequestNet: { logic_requestnet_t *netdata = static_cast<logic_requestnet_t *>(data); result = net_handle(netdata); break; } case kLogicRequestUICommand: break; case kLogicRequestDB: break; default: break; } return result; __LEAVE_FUNCTION return -1; } void AccountController::set_core(logic::Interface *core) { core_ = core; } logic::Interface *AccountController::get_core() { return core_; } int32_t AccountController::ask_login(logic_requestnet_t *netdata) { __ENTER_FUNCTION using namespace pf_base::string; using namespace common::net::packet; char account[ACCOUNT_LENGTH_MAX] = {0}; connection::Login *connection = dynamic_cast<connection::Login *>(netdata->connection); client_tologin::AskLogin *packet = dynamic_cast<client_tologin::AskLogin *>(netdata->packet); safecopy(account, packet->get_account(), sizeof(account)); if (0 == strlen(account) || !checkstr(account, sizeof(account))) { login_toclient::AskLogin msg; msg.set_result(kLoginResultAuthFail); connection->sendpacket(&msg); SLOW_LOG(LOGIC_MODULENAME, "[logic.login] (AccountController::ask_login) account is empty." " account: %s, version: %d", packet->get_account(), _MAIN_VERSION); return kPacketExecuteStatusContinue; } connection->setaccount(packet->get_account()); connection->setstatus(kConnectionStatusLoginWaitingAuth); connection->set_billingtime(TIME_MANAGER_POINTER->get_saved_time()); login_tobilling::Auth *msg = dynamic_cast<login_tobilling::Auth *>( NET_PACKET_FACTORYMANAGER_POINTER ->createpacket(id::login_tobilling::kAuth)); Assert(msg); msg->set_account(packet->get_account()); msg->set_password(packet->get_password()); msg->set_connectionid(connection->getid()); msg->set_token(packet->get_token()); msg->set_ip(connection->getsocket()->host_); CONNECTION_MANAGER_SERVER_POINTER ->syncpacket(msg, kConnectServerTypeBilling); return kPacketExecuteStatusContinue; __LEAVE_FUNCTION return -1; } int32_t AccountController::auth(logic_requestnet_t *netdata) { __ENTER_FUNCTION uint64_t current_threadid = pf_sys::get_current_thread_id(); int32_t result = kPacketExecuteStatusContinue; if (current_threadid == CONNECTION_MANAGER_INCOMING_POINTER->threadid_) { result = auth_toincomming(netdata); } else if (current_threadid == CONNECTION_MANAGER_LOGIN_POINTER->threadid_) { result = auth_tologin(netdata); } return result; __LEAVE_FUNCTION return kPacketExecuteStatusError; } int32_t AccountController::auth_toincomming(logic_requestnet_t *netdata) { __ENTER_FUNCTION using namespace common::net::packet; billing_tologin::Auth *packet = dynamic_cast<billing_tologin::Auth *>(netdata->packet); connection::Login *connection = dynamic_cast<connection::Login *>(netdata->connection); if (strcmp(connection->getaccount(), packet->get_account()) != 0) { SLOW_ERRORLOG(LOGIC_MODULENAME, "[logic.login] (AccountController::auth_toincomming)" " account error." " account: %s, packet account: %s", connection->getaccount(), packet->get_account()); return kPacketExecuteStatusContinue; } uint32_t time = connection->get_billingtime(); enum { kBillingTimeMax = 600000, }; if (TIME_MANAGER_POINTER->get_saved_time() > time + kBillingTimeMax) { SLOW_DEBUGLOG(LOGIC_MODULENAME, "[logic.login] (AccountController::auth) time out."); return kPacketExecuteStatusContinue; } if (kConnectionStatusLoginWaitingAuth == connection->getstatus()) { if (kLoginResultSuccess == packet->get_result() && GLOBAL_VALUES["app_status"] != kAppStatusStop) { connection->setstatus(kConnectionStatusLoginAuthed); CONNECTION_MANAGER_INCOMING_POINTER->erase(connection); CONNECTION_MANAGER_LOGIN_POINTER //发送到登录管理器线程 ->sendpacket(packet, connection->getid()); connection->setstatus(kConnectionStatusLoginProcessTurn); } else { if (kLoginResultOtherOnline == packet->get_result()) { //这个暂时用不到 login_tocenter::RoleKick *msg = dynamic_cast<login_tocenter::RoleKick *>( NET_PACKET_FACTORYMANAGER_POINTER ->createpacket(id::login_tocenter::kRoleKick)); Assert(msg); msg->set_account(packet->get_account()); CONNECTION_MANAGER_SERVER_POINTER ->syncpacket(msg, kConnectServerTypeCenter); } login_toclient::AskLogin msg; msg.set_result(packet->get_result()); if (GLOBAL_VALUES["app_status"] == kAppStatusStop) { msg.set_result(kLoginResultStopService); } CONNECTION_MANAGER_LOGIN_POINTER->sendpacket(&msg, connection->getid()); } } return kPacketExecuteStatusContinue; __LEAVE_FUNCTION return kPacketExecuteStatusError; } int32_t AccountController::auth_tologin(logic_requestnet_t *netdata) { __ENTER_FUNCTION using namespace common::net::packet; billing_tologin::Auth *packet = dynamic_cast<billing_tologin::Auth *>(netdata->packet); connection::Login *connection = dynamic_cast<connection::Login *>(netdata->connection); if (strcmp(connection->getaccount(), packet->get_account()) != 0) { SLOW_ERRORLOG(LOGIC_MODULENAME, "[logic.login] (AccountController::auth_tologin)" " account error." " account: %s, packet account: %s", connection->getaccount(), packet->get_account()); return kPacketExecuteStatusContinue; } CONNECTION_MANAGER_LOGIN_POINTER->add(connection); login_toclient::AskLogin msg; msg.set_result(kLoginResultSuccess); CONNECTION_MANAGER_LOGIN_POINTER->sendpacket(&msg, connection->getid()); uint16_t queuepos = 0; CONNECTION_QUEUE_TURN_POINTER->erase(connection->getaccount(), connection->getid()); if (CONNECTION_QUEUE_TURN_POINTER->addin( connection->getid(), connection->getaccount(), queuepos)) { connection->set_queueposition(queuepos); connection->set_last_sendmessage_turntime( TIME_MANAGER_POINTER->get_tickcount()); login_toclient::TurnStatus msg; msg.set_status(kLoginTurnStatusInTurn); msg.set_number( CONNECTION_QUEUE_TURN_POINTER->calculate_turnnumber(queuepos)); connection->sendpacket(&msg); } else { SLOW_WARNINGLOG(LOGIC_MODULENAME, "[logic.login] (AccountController::auth_tologin)" " the turn is full. account: %s", connection->getaccount()); CONNECTION_MANAGER_LOGIN_POINTER->remove(connection); return kPacketExecuteStatusError; } return kPacketExecuteStatusContinue; __LEAVE_FUNCTION return kPacketExecuteStatusError; } int32_t AccountController::net_handle(logic_requestnet_t *netdata) { __ENTER_FUNCTION if (is_null(netdata) || is_null(netdata->connection) || is_null(netdata->packet)) return kPacketExecuteStatusError; int32_t result = kPacketExecuteStatusContinue; uint16_t packetid = netdata->packet->getid(); switch (packetid) { case id::client_tologin::kAskLogin: result = ask_login(netdata); break; case id::billing_tologin::kAuth: result = auth(netdata); break; default: break; } return result; __LEAVE_FUNCTION return -1; }
本次商业版的开发历时两月,主要的任务是完成或至少理清一种游戏服务器构架,并完成PF核心的升级(商业版本的目前版本为1.0.5d)。github
本次完成了一种服务器的构架,并支持构架扩展(重量级和轻量级)。未完成的任务是游戏的DEMO制做,主要缘由是客户端方面引擎的不熟悉,由于本次将使用我未接触过的cocos2dx引擎。数据库
这次的服务器支持共享缓存(以共享内存做为数据缓存,并能够经过缓存进行数据库查询)。服务器分为消费服务器、共享缓存、登录服务器、数据服务器、中心服务器、游戏服务器。游戏服务器的设计中支持跨服登录,跨服的数据共享,跨服的数据保存。逻辑系统使用MVC模式,包括脚本都使用统一的模式管理。windows
性能上这次中心服务器和游戏服务器分别有一个共享缓存服务器,一组正常的服务器至少有七个服务器(其中消费服务器能够共享)。在没有场景服务的测试和压力测试下,服务器的平均负载为0.3,即单个CPU(线程)的占用为30%。内存为游戏服务器支持5000的玩家缓存状况下,占用为1.6G。其中场景和链接的CPU占用和内存消耗占时能够计算出来,争取作到单CPU能够流畅运行,内存最大的峰值(包括脚本占用)为5G便可。缓存
消费服务器功能为帐号验证和游戏中点卡或充值服务。服务器
数据服务器为多线程模式,主要提供数据库查询服务器,每一个线程对应一个数据库链接器,保证数据库可以快速查询。线程使用线程池管理,分为查询和保存的线程池,将数据库进行读写分离。网络
共享缓存做为之内存共享为基础,用来对数据进行缓存,主要是数据库方面的缓存。多线程
登录服务器做为第一个与客户端链接的验证,扮演着网关的角色。
中心服务器做为控制游戏服务器和登录服务器的中心指挥,做为整个应用中的核心,在中心服务器上存储着角色的在线信息以及全局信息(排行、邮件等功能)。
游戏服务器主要做为玩家逻辑和场景服务使用,在设计中每一个游戏服务器能够承载不一样的场景,进行分布式数据管理同步(压力分布)。在重量级中,场景数目和复杂度太高的状况下这是必须的。
客户端请求登录游戏服务器,服务器收到请求会先请求中心服务器进行验证,注意这里的游戏服务器所请求的中心服务器是跨服原服务器所在的服务器。验证成功后,进行共享内存加载数据,共享缓存夸服时存在一张以中心ID为HASH的链接到对应数据服务器的链接ID列表。这样登录的时候就能够找到玩家所在的数据服务器,进行数据的加载,实现跨服功能。
如下只展现linux部分,PF商业版同时支持windows运行。
一、 项目管理器(WEB)
结合PF项目管理文件,能够方便的进行项目管理,主要是用于生成不一样平台的编译脚本,之后的功能将会更加完善。
二、 协议管理器(WEB)
这里指的是静态包协议管理,也就是说在发送的时候数据是静态的,也就是说有固定的方法设置和获取数据。在PF核心中支持使用其余协议,如protobuf、amf等。
三、 验证服务器
四、 数据服务器
五、 登录服务器
六、 中心缓存服务器
七、中心服务器
八、游戏缓存服务器
九、游戏服务器
十、后台运行
明日将分享项目管理器和网络包管理器的制做原理。
开篇语
咱们没有大神,只有解决问题的人。
咱们没有强悍的技术,只有一颗向往简单的心。
咱们没有惊人的理论,只有一堆难以想象的妄想。
咱们不须要复杂,只须要够简洁。
咱们不须要固定的思惟,只须要你能想获得。
PF托管地址
https://github.com/viticm/plainframework1
PF安装教程
http://www.cnblogs.com/lianyue/p/3974342.html
PF交流QQ群
348477824