從RPC開始(一)

来源:http://www.cnblogs.com/storyhare/archive/2017/01/07/6259801.html
-Advertisement-
Play Games

這是一篇關於純C++RPC框架的文章。所以,我們先看看,我們有什麼? 1、一個什麼都能幹的C++。(前提是,你什麼都幹了) 2、原始的Socket介面,還是C API。還得自己去二次封裝... 3、C++11,這是最令人興奮的。有了它,才能夠有這篇文章;否則,CORBA之類的才是唯一的選擇。(因為需 ...


這是一篇關於純C++RPC框架的文章。所以,我們先看看,我們有什麼?

  1、一個什麼都能幹的C++。(前提是,你什麼都幹了)

  2、原始的Socket介面,還是C API。還得自己去二次封裝...

  3、C++11,這是最令人興奮的。有了它,才能夠有這篇文章;否則,CORBA之類的才是唯一的選擇。(因為需要代碼生成)

 

那麼,我們沒有什麼,或者需要什麼?

  1、一套完善的序列化框架;在不同的進程間傳輸數據,序列化是第一步,如何可靠且方便地將對象轉化為二進位(或者其他格式),在對端則是如何正確且安全地將其從二進位恢復為對象。

  2、完善的底層通信協議;其需要提供合適的語義抽象:服務端支持怎樣的併發,是單客戶單訪問,還是多訪問;而客戶端的併發模型由服務端決定。當然,還需要健壯且足夠的介面抽象,畢竟分散式環境,“一切皆有可能”,需要應對各種問題。

  3、一個可用的反射系統。是的,需要在C++環境下建立一個反射系統。這一步是最為關鍵的,其由C++11支持。因為,我們需要註冊一個類的各種信息,以供RPC調用。

 

當然,本文是提綱式的;也就是,在這裡暫時只會講【目標】——一個可用的C++RPC所需要的全部組件。而更詳細的內容,即如何構建這些組件,將由後續篇章回答。

 

一、序列化

  在分散式環境下,序列化是永遠繞不過的一個坎;而作為一個支撐性組件,其所需要提供不只是“可用”,而是易用且安全!安全!重要的事說兩遍。我們不能夠約定從網路傳來的內容,代表了什麼;而是其本身必須帶有信息,告訴我們它是什麼。

  在純C++環境下,要從零開始構建一個序列化框架,是困難的。畢竟語言本身並沒有提供什麼保證。所幸的是,C++並非完全沒有提供,只是需要我們去發掘。template,模板可以給我們所需要的一切;C++中最令人興奮的部分,其提供了另一個簡單且可靠的擴展模型:通過特化模板,能夠提供類似面向對象的“介面”。當然,需要的還不止這些,我們需要更強大的工具:模板元編程,由其來提供所需要的類型信息(在我的系統中有兩種擴展方式:特化模板和成員函數,後者需要類型信息)。

  下麵將是我們需要完成的目標:

Buffer buffer;
Object obj1;
//序列化
Serialize(&buffer, obj1);

Object obj2;
//反序列化
Deserialize(&buffer, obj2);

  其中的buffer,便是我們的成果;其以二進位保存了對象。當然,還有許多的細節需要補充。

 

二、通信

  UDP還是TCP,這是一個需要糾結的問題。但我們的關註點並不在這,我們需要一個完善的、健壯的通信組件。為了完成這個目標,需要付出一些努力:併發模型、中斷與超時通知。前者是整個RPC框架的語義保證,我們需要保證調用語義的完整性:客戶端的併發訪問請求,到了服務端不能變成串列請求;而普通的通信協議,並不能夠直接提供這點,我選擇了從零開始構建。中斷與超時,是整個調用語義,所面臨的最大挑戰;所以,我們需要合適的通知,以決定如何進行下一步操作。

  當然,UDP與TCP,依舊是一個重要的話題;我的實現,提供了二者的完整實現,所需的只是,選擇。

 

三、反射

  在C++的世界里,講這個話題是不合時宜的。畢竟,無論怎樣的努力,在一個沒有完整運行時環境的語言里,“反射”這樣奢侈的東西,只是一個夢想。但,我們並不是想要重新打造一門語言,而僅僅是給我們的RPC提供一些服務而已。

  在RPC的世界里講“反射”並不是一件突兀的事。看一看,各種沒有IDL的RPC在Java里的實現,無一不是使用了反射這一技術。是的,我的RPC里並沒有IDL,我並不打算再創建一門語言(我有一個腳本語言),哪怕只是一個DSL(領域特定語言)。為了“封裝”類型的各種信息:構造函數、析構函數以及一些我們需要的方法。反射,提供了最合適的語義。

  我的RPC是非侵入式的,在不改變任何原有的代碼的前提下,提供相應的RPC調用。而這一“調用”通過反射來實現。

 

四、RPC

  前面三大組件,和我的RPC並沒有什麼必然的聯繫。但沒有這三個組件,我的RPC框架,將不復存在。所以,最後再來講講我們的主角:RPC。

  其實,RMI(遠程方法調用)更合適一點。我的RPC提供了3中“對象”:

    1、由單一客戶端獨占的,非共用對象;只有該客戶端能夠訪問該對象,其創建和析構,都由一個客戶端發起和執行。

    2、服務對象,這在服務端本身是一個“服務”;也就是其本身是一個單例,因此,所有客戶都是直接在一個對象上,執行各種請求;該對象的構造和析構,可由服務端的本地服務管理框架(我的另一個東西)管理。這個方式,提供了“服務化”的最佳語義;當然,也就需要面對併發。

    3、註冊對象,其也是全局可訪問的,所有客戶端都可以發送請求;不同的是,其是由服務端的某段代碼顯示註冊的,該對象的所有權也由其持有;客戶端只能訪問其介面。一旦服務端取消了註冊,便也消失在所有的客戶端眼前,並且是可能在任何時刻取消註冊,即使有請求還在路上(當然,有請求正在執行,需要等待其執行完成)。

  還有一個重要的事情,我只提供了,同步訪問;因為,我有一個分散式消息系統,可提供非同步服務(這隻是托詞,懶,而已)。

  其實,在擁有了前面的三個組件後,RPC本身便只剩下,需不需要構建,而不是如何。這樣,我們也就可以將重心轉向RPC的語義保證上了。一般有三種語義可以提供:至少一次、至多一次,可能一次。分別代表如下3中結果:

    1、該請求被執行,因為我們將重覆地發送請求,直到答覆。也就意味著,該請求可能被重覆執行多次。

    2、該請求被執行,我們會一直發送重覆的請求,直到答覆。但服務端,將識別這些重覆的請求,並只會執行一次。

    3、該請求被髮送,但我們並不保證被執行;因為,我們沒有等待答覆。

  對於通用的RPC,除了“至多一次”,並沒有其他的選擇。當然,為了完成這點,需要一些努力,所幸並不困難。我的RPC正是提供這樣的調用語義。

  我們將要構建的RPC並沒有使用IDL。所以,客戶端的訪問,將會是顯示的RPC調用;而非是其他框架所宣傳的,能夠完全屏蔽本地和分佈,但我們是在C++的環境下,要完全屏蔽,是不可能的;所以,我所提供的調用方式,並沒有排除原始的方案。其與本地調用的不同是:需要統一從一個RPC客戶端對象中傳入所需要的對象名字,以及在方法調用時,需要一個額外的方法名字。

  比如:

RPCClient client("Something");
int val = client.Invoke("GetValue", 12, "I Want ...").To<int>();

  當然,如果你不習慣這樣的方式(你會習慣的);我還提供了類似IDL的功能:代碼生成。其能夠將上面的顯示訪問,封裝起來,提供和本地調用完全一樣的方式:

#include "Generated\\Something.h"//這個頭文件是生成的

Something obj;
int val = obj.GetValue(12, "I Want ...");

  而在服務端則,使用如下方式提供遠程對象:

Class<Somthing>* type = GetServiceAs<ReflectionService>()->Register<Something>();//也可以重新命名:Register<Something>("OtherName");
type->AddMethod("GetValue", &Somthing::GetValue);//也可註冊重載函數(方式後面再講)

  總之,本篇,完。

  PS:如需,請期待下一篇——序列化。

  PS:以及,下下篇——通信。

  PS:還有,下下下篇——反射。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一.方法: ContainerFromIndex:返回 ItemCollection 中指定索引處的項的容器。 ContainerFromItem:返回與制定的項對應的容器(ComboxItem等條目控制項)。 Equals(Object):確定製定的Object是否等於當前的Object。 Fina ...
  • Linq之Expression進階 Lambda表達式 "Lambda表達式"是一個匿名函數,是一種高效的類似於函數式編程的表達式,Lambda簡化了開發中需要編寫的代碼量。它可以包含表達式和語句,並且可用於創建委托或表達式目錄樹類型,支持帶有可綁定到委托或表達式樹的輸入參數的內聯表達式。所有Lam ...
  • 委托是一個類,它定義了方法的類型,使得可以將方法當作另一個方法的參數來進行傳遞。事件是一種特殊的委托。 1.委托的聲明 (1). delegate delegate我們常用到的一種聲明 Delegate至少0個參數,至多32個參數,可以無返回值,也可以指定返回值類型。 例:public delega ...
  • APS.NET MVC中(以下簡稱“MVC”)的每一個請求,都會分配給相應的控制器和對應的行為方法去處理,而在這些處理的前前後後如果想再加一些額外的邏輯處理。這時候就用到了過濾器。 MVC支持的過濾器類型有四種,分別是:Authorization(授權),Action(行為),Result(結果)和 ...
  • 本篇博文,給大家講解一下裝飾模式,還是老樣子,有一個簡單的例子逐步演繹 一、舉例 用一個簡單的控制台實現 一個人穿各種各樣衣服 的功能 然後我們會很自然的寫出一下代碼: 先寫一個Person類 然後客戶端調用這個Person類 這樣就寫完了。 二、演繹 ①現在,我各種裝扮都寫到了Person類中,有 ...
  • 1 OAuth2解決什麼問題的? 舉個慄子先。小明在QQ空間積攢了多年的照片,想挑選一些照片來列印出來。然後小明在找到一家提供線上列印並且包郵的網站(我們叫它PP吧(Print Photo縮寫 😂))。 那麼現在問題來了,小明有兩個方案來得到列印的服務。 針對方案(1):小明要去下載這些照片,然後 ...
  • 如何快速開發Xamarin.Forms的Plugin?自己開發的Plugin如何使用Nuget打包?本地Package如何參照引用?本文通過TextToSpeech實例為你講解。 ...
  • 配置一個如上圖所示的菜單 1.打開文件MpaNavigationProvider.cs 【..\MyCompanyName.AbpZeroTemplate.Web\Areas\Mpa\Startup\MpaNavigationProvider.cs】 添加如下代碼(如下圖所示) .AddItem(n ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...