欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

FFRPC應(yīng)用 Client/Server使用及原理解析

 更新時間:2019年08月24日 10:29:28   作者:知然  
這篇文章主要介紹了FFRPC應(yīng)用 Client/Server使用及原理解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下

摘要:

Ffrpc 進(jìn)行了重構(gòu),精簡了代碼,代碼更加清晰簡潔,幾乎完美的達(dá)到了我的預(yù)想。接下來將寫幾遍文章來介紹ffrpc可以做什么。簡單總結(jié)ffrpc的特性是:

  • Ffrpc是c++ 網(wǎng)絡(luò)通信庫
  • 全異步 + 回調(diào)函數(shù) 機(jī)制
  • 支持普通二進(jìn)制協(xié)議、protobuf、thrift
  • 基于Broker模式設(shè)計(jì)
  • 設(shè)計(jì)精巧,代碼量小,核心ffrpc的代碼只有1000行
  • 接口的性能監(jiān)控是集成式的,使用者自動獲得了接口性能數(shù)據(jù),方便優(yōu)化接口

普通二進(jìn)制協(xié)議示例

Ffrpc實(shí)現(xiàn)了一個最基本的二進(jìn)制序列化方法,基本的原理就是如果是固定長度那么就直接拷貝,如果是字符串,就先拷貝長度再拷貝內(nèi)容。所以只支持向后擴(kuò)展字段,對其他語言支持也不方便,但如果只是c++語言間傳遞消息,則顯得非常的方便和高效。比如網(wǎng)游服務(wù)器中各個進(jìn)程的通信可以采用這種最簡單的二進(jìn)制協(xié)議。Ffrpc中定義了一個工具類ffmsg_t來定義二進(jìn)制消息.

消息定義:

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;
  };
};

讀者可以看到,ffmsg_t中提供了流式的序列化方法,使得序列化變得很容易。設(shè)計(jì)服務(wù)器消息的時候,需要注意的點(diǎn)有:

  • 在設(shè)計(jì)服務(wù)器接口的時候,每個接口接受一個消息作為參數(shù),一個處理完畢返回一個消息,這是最傳統(tǒng)的rpc模式。Ffrpc中采用這樣的設(shè)計(jì)理念以簡化和規(guī)范化接口設(shè)計(jì)。如果使用ffmsg_t定義消息,本人推薦的定義風(fēng)格類似上面的代碼這樣。上面定義的是echo接口的輸入消息和輸出消息,但是都定義在echo_t結(jié)構(gòu)內(nèi)可以清晰的表明這是一對接口消息。
  • 傳統(tǒng)的服務(wù)器接口會為每個接口定義一個cmd,然后通過cmd反序列化成特定的消息調(diào)用特定的接口,ffrpc省略了cmd的定義,而是直接采用消息名稱作為cmd,比如在ffrpc中注冊的接口接受echo_t的消息,那么收到echo_t的消息自然而言的是調(diào)用這個接口
  • 接口定義的時候必須的同時制定輸入消息和輸出消息
  • Ffmsg_t支持普通類型,字符串類型、stl類型。

echo服務(wù)的實(shí)現(xiàn)代碼:

struct echo_service_t
{
  //! echo接口,返回請求的發(fā)送的消息ffreq_t可以提供兩個模板參數(shù),第一個表示輸入的消息(請求者發(fā)送的)
  //! 第二個模板參數(shù)表示該接口要返回的結(jié)果消息類型
  void echo(ffreq_t<echo_t::in_t, echo_t::out_t>& req_)
  {
    echo_t::out_t out;
    out.data = req_.msg.data;
    LOGINFO(("XX", "foo_t::echo: recv %s", req_.msg.data.c_str()));

    req_.response(out);
  }
};
echo_service_t foo;
  //! broker客戶端,可以注冊到broker,并注冊服務(wù)以及接口,也可以遠(yuǎn)程調(diào)用其他節(jié)點(diǎn)的接口
  ffrpc_t ffrpc_service("echo");
  ffrpc_service.reg(&echo_service_t::echo, &foo);

  if (ffrpc_service.open(arg_helper))
  {
    return -1;
}

這樣就定義了echo服務(wù),echo服務(wù)提供了一個接口,接受echo_t::in_t消息,返回echo_t::out_t消息。由此可見使用ffrpc定義服務(wù)的步驟是:

l 定義消息和接口

將接口注冊到ffrpc的示例中,ffpc提供了reg模板方法,會自動的分析注冊的接口使用神馬輸入消息,從而保證如果echo_t::in_t消息到來一定會調(diào)用對應(yīng)的接口

Ffrpc工作的核心是broker,簡單描述broker的作用就是轉(zhuǎn)發(fā)消息。Ffrpc的client和server是不直接連接的,而是通過broker轉(zhuǎn)發(fā)消息進(jìn)行通信。

這樣的好處是server的位置對于client是完全透明的,這也是broker模式最精髓的思想。所以ffrpc天生就是scalability的。Ffrpc的client比如要調(diào)用echo服務(wù)的接口,完全不需要知道serverr對應(yīng)的位置或者配置,只需要知道echo服務(wù)的名字。有人可能擔(dān)憂完全的broker轉(zhuǎn)發(fā)可能會帶來很大開銷。

Broker保證了消息轉(zhuǎn)發(fā)的最佳優(yōu)化,如果client或者server和broker在同一進(jìn)程,那么消息直接是內(nèi)存間傳遞的,連序列化都不需要做,這也是得益于broker模式,broker模式的特點(diǎn)就是擁有很好的scalability。這樣無論是簡單的設(shè)計(jì)一個單進(jìn)程的server還是設(shè)計(jì)成多進(jìn)程分布式的一組服務(wù),ffrpc都能完美勝任。
調(diào)用echo服務(wù)的client示例:

struct echo_client_t
{
  //! 遠(yuǎn)程調(diào)用接口,可以指定回調(diào)函數(shù)(也可以留空),同樣使用ffreq_t指定輸入消息類型,并且可以使用lambda綁定參數(shù)
  void echo_callback(ffreq_t<echo_t::out_t>& req_, int index, ffrpc_t* ffrpc_client)
  {
    if (req_.error())
    {
      LOGERROR(("XX", "error_msg <%s>", req_.error_msg()));
      return;
    }
    else if (index < 10)
    {
      echo_t::in_t in;
      in.data = "helloworld";
      LOGINFO(("XX", "%s %s index=%d callback...", __FUNCTION__, req_.msg.data.c_str(), index));
      sleep(1);
      ffrpc_client->call("echo", in, ffrpc_ops_t::gen_callback(&echo_client_t::echo_callback, this, ++index, ffrpc_client));
    }
    else
    {
      LOGINFO(("XX", "%s %s %d callback end", __FUNCTION__, req_.msg.data.c_str(), index));
    }
  }
};
ffrpc_t ffrpc_client;
  if (ffrpc_client.open(arg_helper))
  {
    return -1;
  }
  
  echo_t::in_t in;
  in.data = "helloworld";
  echo_client_t client;
  ffrpc_client.call("echo", in, ffrpc_ops_t::gen_callback(&echo_client_t::echo_callback, &client, 1, &ffrpc_client));

使用ffrpc調(diào)用遠(yuǎn)程接口,只需要制定服務(wù)名和輸入消息,broker自動定位echo服務(wù)的位置,本示例中由于ffrpc的client和server在同一進(jìn)程,那么自動通過內(nèi)存間傳遞,如果server和broker在同一進(jìn)程,而client在其他進(jìn)程或者物理機(jī)上,則broker和server之間的傳遞為內(nèi)存?zhèn)鬟f,broker和client的消息傳遞為tcp傳輸,這就跟自己寫一個tcp的server收到消息投遞給service的接口,然后將消息再通過tcp投遞給client。但是必須看到,ffrpc完全簡化了tcp server定義,并且更加scalability,甚至完全可以用來進(jìn)程內(nèi)多線程的通訊。

需要注意的是,ffrpc擁有良好的容錯能力,如果服務(wù)不存在或者接口不存在或者異常等發(fā)生回調(diào)函數(shù)仍然是會被調(diào)用,并且返回錯誤信息,從而使錯誤處理變得更加容易。比如游戲服務(wù)器中client登入gate但是scene可能還沒有啟動的時候,這里就能夠很好的處理,回調(diào)函數(shù)檢查錯誤就可以了。對于回調(diào)函數(shù),對于經(jīng)常使用多線程和任務(wù)隊(duì)列的開發(fā)者一定非常熟悉,回調(diào)函數(shù)支持lambda參數(shù)應(yīng)該算是錦上添花,使得異步的代碼變得更加清晰易懂。

Broker的啟動方式:

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 false -log_level 3");
  
    if (argc == 1)
    {
      printf("usage: %s -broker tcp://127.0.0.1:10241\n", argv[0]);
      return 1;
    }
    arg_helper_t arg_helper(argc, argv);
  
    //! 啟動broker,負(fù)責(zé)網(wǎng)絡(luò)相關(guān)的操作,如消息轉(zhuǎn)發(fā),節(jié)點(diǎn)注冊,重連等
  
    ffbroker_t ffbroker;
    if (ffbroker.open(arg_helper))
    {
      return -1;
    }
  
    sleep(1);
    if (arg_helper.is_enable_option("-echo_test"))
    {
      run_echo_test(arg_helper);    
    }
    else if (arg_helper.is_enable_option("-protobuf_test"))
    {
      run_protobuf_test(arg_helper);
    }
    else
    {
      printf("usage %s -broker tcp://127.0.0.1:10241 -echo_test\n", argv[0]);
      return -1;
    }
  
    ffbroker.close();
    return 0;
  }

Ffrpc中兩個關(guān)鍵的組件broker和rpc,broker負(fù)責(zé)轉(zhuǎn)發(fā)和注冊服務(wù)器,rpc則代表通信節(jié)點(diǎn),可能是client可能是server。即使是多個服務(wù)器,只需要broker一個監(jiān)聽的端口,其他的服務(wù)只需要提供不同的服務(wù)名即可。

Protobuf協(xié)議示例

Ffrpc 良好的設(shè)計(jì)抽離了對于協(xié)議的耦合,使得支持protobuf就增加了10來行代碼。當(dāng)然這也是由于protobuf生成的消息都繼承message基類。當(dāng)我實(shí)現(xiàn)thrift的時候,事情就稍微麻煩一些,thrift生成的代碼更加簡潔,但是生成的消息不集成基類,需要復(fù)制粘貼一些代碼。

Protobuf的定義文件:

package ff;

message pb_echo_in_t {
 required string data = 1;
}
message pb_echo_out_t {
 required string data = 1;
}

我們?nèi)匀辉O(shè)計(jì)一個echo服務(wù),定義echo接口的消息,基于ffrpc的設(shè)計(jì)理念,每個接口都有一個輸入消息和輸出消息。

Echo服務(wù)的實(shí)現(xiàn)代碼:

struct protobuf_service_t
{
  //! echo接口,返回請求的發(fā)送的消息ffreq_t可以提供兩個模板參數(shù),第一個表示輸入的消息(請求者發(fā)送的)
  //! 第二個模板參數(shù)表示該接口要返回的結(jié)果消息類型
  void echo(ffreq_t<pb_echo_in_t, pb_echo_out_t>& req_)
  {
    LOGINFO(("XX", "foo_t::echo: recv data=%s", req_.msg.data()));
    pb_echo_out_t out;
    out.set_data("123456");
    req_.response(out);
  }
};
protobuf_service_t foo;
  //! broker客戶端,可以注冊到broker,并注冊服務(wù)以及接口,也可以遠(yuǎn)程調(diào)用其他節(jié)點(diǎn)的接口
  ffrpc_t ffrpc_service("echo");
  ffrpc_service.reg(&protobuf_service_t::echo, &foo);

  if (ffrpc_service.open(arg_helper))
  {
    return -1;
  }

跟使用ffmsg_t的方式幾乎是一樣的,ffreq_t 的msg字段是輸入的消息。

調(diào)用echo服務(wù)器的client的示例代碼

struct protobuf_client_t
{
  //! 遠(yuǎn)程調(diào)用接口,可以指定回調(diào)函數(shù)(也可以留空),同樣使用ffreq_t指定輸入消息類型,并且可以使用lambda綁定參數(shù)
  void echo_callback(ffreq_t<pb_echo_out_t>& req_, int index, ffrpc_t* ffrpc_client)
  {
    if (req_.error())
    {
      LOGERROR(("XX", "error_msg <%s>", req_.error_msg()));
      return;
    }
    else if (index < 10)
    {
      pb_echo_in_t in;
      in.set_data("Ohnice");
      LOGINFO(("XX", "%s data=%s index=%d callback...", __FUNCTION__, req_.msg.data(), index));
      sleep(1);
      ffrpc_client->call("echo", in, ffrpc_ops_t::gen_callback(&protobuf_client_t::echo_callback, this, ++index, ffrpc_client));
    }
    else
    {
      LOGINFO(("XX", "%s %d callback end", __FUNCTION__, index));
    }
  }
};

  ffrpc_t ffrpc_client;
  if (ffrpc_client.open(arg_helper))
  {
    return -1;
  }
  
  protobuf_client_t client;
  pb_echo_in_t in;
  in.set_data("Ohnice");

  ffrpc_client.call("echo", in, ffrpc_ops_t::gen_callback(&protobuf_client_t::echo_callback, &client, 1, &ffrpc_client));

Protobuf的優(yōu)點(diǎn)是:

支持版本,這樣增加字段變得更加容易

Protobuf是支持多語言的,這樣可以跟其他的語言也可以通訊

Thrift協(xié)議的示例

Thrift 定義文件:

namespace cpp ff 

struct echo_thrift_in_t {   
 1: string data
}

struct echo_thrift_out_t {   
 1: string data
}

Thrift 的服務(wù)器實(shí)現(xiàn)代碼:

struct thrift_service_t
{
  //! echo接口,返回請求的發(fā)送的消息ffreq_t可以提供兩個模板參數(shù),第一個表示輸入的消息(請求者發(fā)送的)
  //! 第二個模板參數(shù)表示該接口要返回的結(jié)果消息類型
  void echo(ffreq_thrift_t<echo_thrift_in_t, echo_thrift_out_t>& req_)
  {
    LOGINFO(("XX", "foo_t::echo: recv data=%s", req_.msg.data));
    echo_thrift_out_t out;
    out.data = "123456";
    req_.response(out);
  }
};
thrift_service_t foo;
  //! broker客戶端,可以注冊到broker,并注冊服務(wù)以及接口,也可以遠(yuǎn)程調(diào)用其他節(jié)點(diǎn)的接口
  ffrpc_t ffrpc_service("echo");
  ffrpc_service.reg(&thrift_service_t::echo, &foo);

  if (ffrpc_service.open(arg_helper))
  {
    return -1;
  }
  
  ffrpc_t ffrpc_client;
  if (ffrpc_client.open(arg_helper))
  {
    return -1;
}

調(diào)用 echo的client的示例:

struct thrift_client_t
{
  //! 遠(yuǎn)程調(diào)用接口,可以指定回調(diào)函數(shù)(也可以留空),同樣使用ffreq_t指定輸入消息類型,并且可以使用lambda綁定參數(shù)
  void echo_callback(ffreq_thrift_t<echo_thrift_out_t>& req_, int index, ffrpc_t* ffrpc_client)
  {
    if (req_.error())
    {
      LOGERROR(("XX", "error_msg <%s>", req_.error_msg()));
      return;
    }
    else if (index < 10)
    {
      echo_thrift_in_t in;
      in.data = "Ohnice";
      LOGINFO(("XX", "%s data=%s index=%d callback...", __FUNCTION__, req_.msg.data, index));
      sleep(1);
      ffrpc_client->call("echo", in, ffrpc_ops_t::gen_callback(&thrift_client_t::echo_callback, this, ++index, ffrpc_client));
    }
    else
    {
      LOGINFO(("XX", "%s %d callback end", __FUNCTION__, index));
    }
  }
};
ffrpc_t ffrpc_client;
  if (ffrpc_client.open(arg_helper))
  {
    return -1;
  }
  
  thrift_client_t client;
  echo_thrift_in_t in;
  in.data = "Ohnice";

ffrpc_client.call("echo", in, ffrpc_ops_t::gen_callback(&thrift_client_t::echo_callback, &client, 1, &ffrpc_client));

Thrift的優(yōu)缺點(diǎn):

  • Thrift 更加靈活,支持list和map,而且可以嵌套
  • 支持N種語言
  • 官方的版本需要依賴boost,ffrpc從中提取出一個最基本的c++版本,只有頭文件,不依賴boost

總結(jié)

  • Ffrpc是基于c++的網(wǎng)絡(luò)通訊庫,基于broker模式scalability和 易用性是最大的優(yōu)點(diǎn)
  • 使用ffrpc進(jìn)行進(jìn)程間通訊非常的容易,定義服務(wù)和接口就行了,你除了使用ffmsg_t最傳統(tǒng)的消息定義,也可以使用google protobuf和facebook thrift。
  • Ffrpc是全異步的,通過回調(diào)函數(shù)+lambda方式可以很容易操作異步邏輯。
  • Ffrpc 接下來會有更多的示例,當(dāng)系統(tǒng)復(fù)雜時,ffrpc的優(yōu)勢將會更加明顯。
  • Github的地址: https://github.com/fanchy/FFRPC

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • C++中char*轉(zhuǎn)換為LPCWSTR的解決方案

    C++中char*轉(zhuǎn)換為LPCWSTR的解決方案

    最近在學(xué)習(xí)C++,遇到了一個char*轉(zhuǎn)換為LPCWSTR的問題,通過查找資料終于解決了,所以下面這篇文章主要介紹了C++中char*轉(zhuǎn)LPCWSTR的解決方案,文中通過詳細(xì)的示例代碼介紹的很詳細(xì),有需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-01-01
  • C++?TCP網(wǎng)絡(luò)編程詳細(xì)講解

    C++?TCP網(wǎng)絡(luò)編程詳細(xì)講解

    TCP/IP是一種面向連接的、可靠的、基于字節(jié)流的傳輸層通信協(xié)議,它會保證數(shù)據(jù)不丟包、不亂序。TCP全名是Transmission?Control?Protocol,它是位于網(wǎng)絡(luò)OSI模型中的第四層
    2022-09-09
  • C語言實(shí)現(xiàn)九大排序算法的實(shí)例代碼

    C語言實(shí)現(xiàn)九大排序算法的實(shí)例代碼

    這篇文章主要給大家介紹了關(guān)于C語言實(shí)現(xiàn)九大排序算法的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • c++語言中虛函數(shù)實(shí)現(xiàn)多態(tài)的原理詳解

    c++語言中虛函數(shù)實(shí)現(xiàn)多態(tài)的原理詳解

    這篇文章主要給大家介紹了關(guān)于c++語言中虛函數(shù)實(shí)現(xiàn)多態(tài)的原理的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用c++語言具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • C++鏈表實(shí)現(xiàn)通訊錄設(shè)計(jì)

    C++鏈表實(shí)現(xiàn)通訊錄設(shè)計(jì)

    這篇文章主要為大家詳細(xì)介紹了C++鏈表實(shí)現(xiàn)通訊錄設(shè)計(jì),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • 使用QPainter畫一個3D正方體

    使用QPainter畫一個3D正方體

    這篇文章主要為大家詳細(xì)介紹了使用QPainter畫一個3D正方體,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-08-08
  • C++設(shè)計(jì)模式之享元模式

    C++設(shè)計(jì)模式之享元模式

    這篇文章主要介紹了C++設(shè)計(jì)模式之享元模式,本文講解了什么是享元模式、享元模式代碼實(shí)例、享元模式的優(yōu)點(diǎn)等內(nèi)容,需要的朋友可以參考下
    2014-10-10
  • 關(guān)于C語言和命令行之間的交互問題

    關(guān)于C語言和命令行之間的交互問題

    這篇文章主要介紹了C語言和命令行之間的交互,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-07-07
  • 軟件構(gòu)建工具makefile基礎(chǔ)講解

    軟件構(gòu)建工具makefile基礎(chǔ)講解

    這篇文章介紹了軟件構(gòu)建工具makefile,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-12-12
  • C語言各類操作符全面講解

    C語言各類操作符全面講解

    C?語言提供了豐富的操作符,有:算術(shù)操作符,移位操作符,位操作符,賦值操作符,單目操作符,關(guān)系操作符,邏輯操作符,條件操作符等。接下了讓我們詳細(xì)了解掌握它
    2022-05-05

最新評論