ffrpc-c++進程間(伺服器端、用戶端)通訊架構

來源:互聯網
上載者:User
FFRPC

github 地址 https://github.com/fanchy/FFRPC

FFRPC 已經陸陸續續開發了1年,6月6日這天終於完成了我比較滿意的版本,暫稱之為 V0.2,FFRPC實現了一個C++版本 的非同步進程間通訊庫。我本身是做遊戲伺服器程式的,在伺服器程式領域,系統是分布式的,各個節點需要非同步進行通訊, 我的初衷是開發一個易用、易測試的進程間socket通訊組件。實際上FFRPC 已經是一個架構。

FFRPC 主要特性
  • FFRPC 採用Epoll Edge Trigger模式,這裡特別提一下ET是因為在非同步工作模式,ET方式才是epoll最簡單也是最高效的方式 網上的很多文章寫LT簡單易用,那純碎是沒有理解ET的精髓之所在,如果讀者想要從ffrpc中探究一下ET的奧妙,提醒讀者的是 請把Epoll 看成一個狀態機器!FFRPC 採用Broker模式,這樣的好處是 Scalability!! 在遊戲領域的開發人員一定很熟悉Master/Gateway/Logic Server的概念, 實際上Master 實際上扮演的Broker master的角色,而gateway扮演的是Broker slave的角色,Broker Slave負責轉寄用戶端的 請求到Logic Service,提供一個轉寄層雖然會增加延遲,但是系統變得可擴充,大大提高了輸送量,這就是Scalability!! 而Broker master負責管理所有的Master Slave,負責負載平衡。不同的client分配不同的Broker SLave。
  • FFRPC 就是基於以上的思路,有如下四個關鍵的概念:
    • 一:broker master 負責負載平衡,同步所有節點的資訊,所有的slave broker和rpc service/ rpc cleint都要串連broker master。
    • 二:slave broker負責完成service和client間轉寄訊息,如果service、client和broker在同一進程,那麼直接在記憶體間投遞訊息, 這是v0。2的重要的最佳化,v0。1時沒有此功能,網友很多反應這個問題,看來大夥對最佳化還是太敏感! 另一個創新之處在於ffmsg_t,封裝了訊息的序列化和還原序列化,我已經厭倦了protobuff,如果你也研究了為每個訊息定義cmd 和為cmd寫switch(有些人可能已經用上註冊回呼函數,但還有更好用的)。實際上定義訊息結構體時一個訊息本身就是獨一無二的, 所以為什麼我們還要給訊息在定義一個cmd呢?比如定義了struct echo_t{int a;}訊息,echo_t名稱本身就是獨一無二的,否則編譯 器肯定報錯了,那麼為什麼不直接用echo_t這個名稱作為cmd呢?在FFRPC中可以使用TYPE_NAME(echo_t)獲得訊息體名稱字串, 是滴TYPE_NAME是一個很有意思的實現,c++中並沒喲關鍵字可以擷取一個類的名稱,但是所有的編譯器都實際上已經提供了這個功能! 詳情請看源碼。有讀者可能會糾結使用訊息體結構的名稱做cmd固然省事,但是浪費了流量!32位的cmd總是比字串省流量,是的這個 結論雖然我很不喜歡(我總是懶的最佳化,除非...被逼的),但是他是對的!ffrpc中很好的解決了這個問題,當每個節點初始化時都要 註冊到broker master,這時所有的訊息都會在master中分配一個唯一的msg id,這樣就可以用整數1代表echo_t結構了,由於每個節點 都知道echo_t到1的映射,所以程式員再也不用手動定義cmd了,broker唯一初始化時動態定義。
    • 三:ffrpc service,提供介面的模組,也就就是服務端,通過ffrpc類註冊的介面基於非同步模式,推薦的模式是每個訊息都返回 一個結果訊息
    • 四:ffrpc client是調用的ffrpc service的模組,基於非同步模式,記住服務名成和訊息名稱唯一的確定一個介面,這個c++的類和類介面 概念是一致的,而且調用遠程介面時可以指定回呼函數,而且回呼函數還支援lambda參數綁定!
  • 想快速見證ffrpc庫的魅力可以小看如下的樣本,只要你有linux系統,可以1分鐘內測試這個樣本,ffrpc沒有其他依賴,提醒你的是 FFRPC的日誌組件是彩色的哦!
範例程式碼
#include <stdio.h>#include "base/daemon_tool.h"#include "base/arg_helper.h"#include "base/strtool.h"#include "base/smart_ptr.h"#include "rpc/ffrpc.h"#include "rpc/ffbroker.h"#include "base/log.h"using namespace ff;//! 定義echo 介面的訊息, in_t代表輸入訊息,out_t代表的結果訊息//! 提醒大家的是,這裡沒有為echo_t定義神馬cmd,也沒有制定其名稱,ffmsg_t會自動能夠擷取echo_t的名稱struct echo_t{    struct in_t: public ffmsg_t<in_t>    {        void encode()        {            encoder() << data;        }        void decode()        {            decoder() >> data;        }        string data;    };    struct out_t: public ffmsg_t<out_t>    {        void encode()        {            encoder() << data;        }        void decode()        {            decoder() >> data;        }        string data;    };};struct foo_t{    //! echo介面,返回請求的發送的訊息ffreq_t可以提供兩個模板參數,第一個表示輸入的訊息(要求者發送的)    //! 第二個模板參數表示該介面要返回的結果訊息類型    void echo(ffreq_t<echo_t::in_t, echo_t::out_t>& req_)    {        echo_t::out_t out;        out.data = req_.arg.data;        LOGDEBUG(("XX", "foo_t::echo: %s", req_.arg.data.c_str()));        req_.response(out);    }    //! 遠程調用介面,可以指定回呼函數(也可以留空),同樣使用ffreq_t指定輸入訊息類型,並且可以使用lambda綁定參數    void echo_callback(ffreq_t<echo_t::out_t>& req_, int index)    {        LOGDEBUG(("XX", "%s %s %d", __FUNCTION__, req_.arg.data.c_str(), index));    }};int main(int argc, char* argv[]){    //! 美麗的日誌組件,shell輸出是彩色滴!!    LOG.start("-log_path ./log -log_filename log -log_class XX,BROKER,FFRPC -log_print_screen true -log_print_file true -log_level 6");    //! 啟動broker,負責網路相關的操作,如訊息轉寄,節點註冊,重連等    ffbroker_t ffbroker;    ffbroker.open("app -l tcp://127.0.0.1:10241");    //! broker用戶端,可以註冊到broker,並註冊服務以及介面,也可以遠程調用其他節點的介面    ffrpc_t ffrpc_service("echo");    foo_t foo;    ffrpc_service.reg(&foo_t::echo, &foo);    ffrpc_service.open("app -broker tcp://127.0.0.1:10241");    ffrpc_t ffrpc_client;    ffrpc_client.open("app -broker tcp://127.0.0.1:10241");    echo_t::in_t in;    in.data = "helloworld";    //! 你沒有看見get_type_name定義,但是他確定存在    printf("測試擷取類名:%s\n", in.get_type_name());//輸出為:測試擷取類名:echo_t::in_t    for (int i = 0; i < 100; ++i)    {        //! 如你所想,echo介面被調用,然後echo_callback被調用,每一秒重複該過程        ffrpc_client.call("echo", in, ffrpc_ops_t::gen_callback(&foo_t::echo_callback, &foo, i));        sleep(1);    }    sleep(300);    ffbroker.close();    return 0;}

 

總結
  • ffrpc中broker、client、service可以啟動在不同的進程,如果在同一進程,那麼直接記憶體間投遞訊息
  • ffrpc 每個執行個體單獨啟動一個線程和任務隊列,保證service和client的操作都是有序、安全執行緒的。
  • 如果你研究過protobuff、thrift、zeromq、ice等等類庫/架構, 更要試用一下ffrpc。
  • github 地址 https://github.com/fanchy/FFRPC
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.