個人2016年終總結(PF項目框架設計心得分享 2.0rc)

在無數的日夜裏,熬出了多少的黑眼圈,致勤勤懇懇工做的各位朋友與本身。每到了年底的時候總想寫的什麼,主要是爲了回顧以往一年裏到底作了什麼,這即是年終總結的主要意義。在此我將要總結的是和我在技術層面上成長的一個項目,那即是開源的plain framework(簡稱PF),我會在這裏分享一些關於程序設計的一些心得。mysql

  起源

  2014年的7月左右,本着對於本身技術的不斷提升,我正式將以前的plain server項目進行整理,準備寫一個能夠方便使用的框架。具體緣由主要是發覺本身在工做中很是須要,以及技術層面上須要突破,並且也想革新下在此領域裏良莠不齊的格局。
  一我的的野心便成爲了他的動力,到了現在我也仍是這樣想。但是在這方面卻已經有了許多成熟的框架,諸如ACE、 ZeroMQ等,不過卻感受使用起來並不怎麼方便,要麼就是功能太多,要麼就是太單一。做爲一個網絡應用,須要的幾個模塊我便作出了總結:文件、網絡、數據庫、緩存、腳本。這五大部分,是現在應用中很是流行的,相信只要提供好的支持後這樣的框架能夠解決大部分應用的問題。
  特別是作遊戲的朋友,能夠發現一些國內的好框架,好比雲風的skynet。我是在2012年的時候接觸到了,那個時候我剛剛進入這個行業,對於腳本lua也在他的文章裏受益不淺。在此我向這些開源和分享知識的前輩們,表示由衷的感謝。不過skynet是使用C和lua結合的框架,這大概是由於我的愛好的緣由。不過每一個語言都不能盡善盡美,C++的優勢在於對象化,而C呢在於簡潔,其實C++原本是在C的基礎上發展的,是更高層次的語言,因此從自己來講有必定優點,同時便失去簡潔。我對C/C++沒有任何偏好,不過我對第一個讓我入門的PHP感到很是大的興趣,腳本語言的魅力就是對象化而又不失其簡潔,同時我就討厭如JAVA通常的環境配置。
  不管怎樣也好,從語言上來講,每種語言都是方便開發者使用,而PF的初衷也是這樣。
  因而我從2014年開始了長達三年左右的開源過程……

  結構

  從代碼的結構上來講,五大模塊已經所有支持,不過我對結構要求的比較細。可能出於強迫症的緣由,在期間我對該結構進行了無數次的更改。
  basic -- 基礎支持
  cache -- 緩存
  db -- 數據庫
  engine -- 引擎(主控制)
  file -- 文件操做
  net -- 網絡
  script -- 腳本
  sys -- 系統
  util -- 工具

  版本

  在1.0-1.1的版本中,使用了C99的少部分特性,不過是以C++98的標準來編寫的,這樣適合大多數的開發者使用。
  在2.0之後的版本,使用C++11。由於我注意到它能夠簡化編碼,並且彷佛也比較高效,當我徹底替換了C++11的模式後,才發現C++17標準已經出來,實在是讓人意想不到,相比的C還停留在C11階段。從目前來看,C++11的項目不會過期,你們也沒有必要擔憂。

  接口

  待續……git

  編譯

  現階段PF只支持LINUX上的編譯和運行,會在後期支持WINDOWS的版本,由於以前許多朋友們出現了編譯上的一些錯誤,爲了下降編譯的難度將會分開一個單獨的倉庫。
  在2.0rc版本里,在框架目錄下使用make就能夠編譯框架和生成一個簡單的pf_simple測試應用了,這比以前的簡單不少。
  不過須要準備的環境是:升級到支持編譯C++11的gcc、瞭解ODBC的配置。

  測試

/**
 * GLOBALS["default.engine.frame"] = number;      //default 100.
 * GLOBALS["default.net.open"] = bool;            //default false.
 * GLOBALS["default.net.service"] = bool;         //default false.
 * GLOBALS["default.net.service_ip"] = string;    //default "".
 * GLOBALS["default.net.service_port"] = number;  //default 0.
 * GLOBALS["default.net.conn_max"] = number;      //default NET_CONNECTION_MAX.
 * GLOBALS["default.script.open"] = bool;         //default false.
 * GLOBALS["default.script.rootpath"] = string;   //default SCRIPT_ROOT_PATH.
 * GLOBALS["default.script.workpath"] = string;   //default SCRIPT_WORK_PATH.
 * GLOBALS["default.script.bootstrap"] = string;  //default "bootstrap.lua".
 * GLOBALS["default.script.type"] = number;       //default pf_script::kTypeLua.
 * GLOBALS["default.cache.open"] = bool;          //default fasle.
 * GLOBALS["default.cache.service"] = bool;       //default fasle.
 * GLOBALS["default.cache.conf"] = string;        //default "".
 * GLOBALS["default.cache.key_map"] = number;     //default ID_INVALID.
 * GLOBALS["default.cache.recycle_map"] = number; //default ID_INVALID.
 * GLOBALS["default.cache.query_map"] = number;   //default ID_INVALID.
 * GLOBALS["default.db.open"] = bool;             //default fasle.
 * GLOBALS["default.db.type"] = number;           //default kDBConnectorTypeODBC.
 * GLOBALS["default.db.server"] = string;         //default "".
 * GLOBALS["default.db.user"] = string;           //default "".
 * GLOBALS["default.db.password"] = string;       //default "".
 **/

#include "main.h"
#include "net.h"
#include "packet/sayhello.h"

//The script reload function.
void reload() {
  if (is_null(ENGINE_POINTER)) return;
  auto env = ENGINE_POINTER->get_script();
  if (is_null(env)) return;
  env->reload("preload.lua");
}

//The test engine main loop event 1.
int32_t times = 0;
void main_loop(pf_engine::Kernel &engine) {
  std::cout << "main_loop ..." << std::endl;
  ++times;
  if (times > 10)
    std::cout << "main_loop exited by 10 times" << std::endl;
  else
    engine.enqueue([&engine](){ main_loop(engine); });
}

//The test engine main loop event 2.
void main_loop1(pf_engine::Kernel &engine) {
  std::cout << "main_loop1 ..." << std::endl;
  ++times;
  if (times > 20)
    std::cout << "main_loop1 exited by 20 times" << std::endl;
  else
    engine.enqueue([&engine](){ main_loop1(engine); });
}

//Net test.
pf_net::connection::Basic *connector{nullptr};
void main_nconnect(pf_engine::Kernel &engine,
                   pf_net::connection::manager::Connector &mconnector) {
  mconnector.tick();
  if (is_null(connector)) {
    connector = mconnector.connect(
        "127.0.0.1", GLOBALS["default.net.service_port"].uint16());
  } else {
    static uint32_t last_time = 0;
    auto tickcount = TIME_MANAGER_POINTER->get_tickcount();
    if (tickcount - last_time > 5000) {
      SayHello packet;
      packet.set_str("hello ...");
      connector->send(&packet);
      last_time = tickcount;
    }
  }
  engine.enqueue([&engine, &mconnector](){ main_nconnect(engine, mconnector); });
}

//DB test.
void db_test(pf_engine::Kernel &engine) {
  auto db = engine.get_db();
  if (is_null(db)) return;
  if (db->isready()) {
    db_query_t db_query;
    pf_db::Query query(&db_query);
    if (!query.init(db)) return;
    query.set_tablename("t_test");
    query.select("*");
    query.from();
    query.limit(1);
    if (query.execute()) {
      pf_basic::io_cwarn("------------------------db---------------------------");
      db_fetch_array_t fectch_array;
      query.fetcharray(fectch_array);
      pf_basic::io_cdebug("db_test keys: ");
      for (pf_basic::type::variable_t &key : fectch_array.keys)
        std::cout << key.string() << std::endl;
      pf_basic::io_cdebug("db_test values: ");
      for (pf_basic::type::variable_t &val : fectch_array.values)
        std::cout << val.string() << std::endl;
      pf_basic::io_cwarn("------------------------db---------------------------");
    }
  } else {
    engine.enqueue([&engine](){ db_test(engine); });
  }
}

int32_t main(int32_t argc, char * argv[]) {
  /* Base config. */
  GLOBALS["app.debug"] = true;
  GLOBALS["app.name"] = "simple";

  //Net.
  GLOBALS["default.net.open"] = true;
  GLOBALS["default.net.service"] = true;
  GLOBALS["default.net.service_port"] = 12306;

  //DB.
  GLOBALS["default.db.open"] = true;
  GLOBALS["default.db.server"] = "pf_test";
  GLOBALS["default.db.user"] = "root";
  GLOBALS["default.db.password"] = "mysql";

  //Script.
  GLOBALS["default.script.open"] = true;

  /* engine. */
  pf_engine::Kernel engine;
  pf_engine::Application app(&engine);

  /* command handler. */
  app.register_commandhandler("--reload", "lua script reload.", reload);

  /* engine event. */
  engine.enqueue([](){ std::cout << "main loop function1" << std::endl; });
  engine.enqueue([&engine](){ main_loop(engine); });
  engine.enqueue([&engine](){ main_loop1(engine); });
  engine.enqueue([&engine](){ db_test(engine); });

  /* net init. */
  pf_net::connection::manager::Connector mconnector;
  init_net_packets();
  mconnector.init(1);
  engine.enqueue([&engine, &mconnector](){ main_nconnect(engine, mconnector); });

  /* run */
  app.run(argc, argv);
  return 0;
}

  在測試裏面加入了基本的網絡、腳本、數據庫的測試,你們能夠先嚐試摸索一下,從上述代碼中能夠見到如今框架的比1.0版本簡潔許多。github

  在1.0中我就用到了全局變量,在設計的時候感受十分冗雜,因此2.0後統一使用GLOBALS來代替,這樣使用起來也方便。sql

  最後

  匆匆的寫了這麼一些,但願你們不要見怪,等有時間會把這篇文章修改好的。數據庫

  地址

  https://github.com/viticm/plainframeworkbootstrap

相關文章
相關標籤/搜索