plain framework 商業版 開發總結1 updated

天天對着不一樣的計劃,多多少少有一種無形的壓力。特別是對技術很差的我來講,過程當中遇到的問題實在很多,時常糾結良久。時間慢慢流逝,最後雖然感受有些不足,可是也不至於差強人意。商業版的PF核心已經升級到1.0.5版本,增添和完善了許多功能。核心主要完善了網絡模塊、腳本模塊、文件模塊、引擎模塊、緩存模塊等等,並製做了基本的場景插件和AI插件。將來的PF將支持更多的功能,將安裝和使用更加的自動化,執行一個腳本就能完成許多沒必要要的步驟。因此將來的腳本工具是一個必須完成的功能,在此咱們將迎來一個個熱愛開源項目的同仁和期待大家的加入。5月商業版服務器的開發總結,將全面將製做原理和遇到的麻煩分享,但願你們可以一塊兒進步。原理比如是漁網和捕魚的技術,雖然沒有源代碼,我想比源代碼來的更加有價值。若是你們願意,能夠加入咱們的羣共同討論。html

計劃表

  每日都在計劃表中糾結,一步步辛酸,一步步艱難的前行。linux

 

CODE

  部分商業核心代碼,暫時不予開源。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人員招募

開篇語
  咱們沒有大神,只有解決問題的人。
  咱們沒有強悍的技術,只有一顆嚮往簡單的心。
  咱們沒有驚人的理論,只有一堆難以想象的妄想。
  咱們不須要複雜,只須要夠簡潔。
  咱們不須要固定的思惟,只須要你能想獲得。

PF託管地址

  https://github.com/viticm/plainframework1

PF安裝教程

  http://www.cnblogs.com/lianyue/p/3974342.html

PF交流QQ羣

  348477824

相關文章
相關標籤/搜索