基於DotNet Core的RPC框架(一) DotBPE.RPC快速開始

来源:http://www.cnblogs.com/xuanye/archive/2017/05/15/a-dotnet-core-rpc-sln-dotbpe-quickstart.html
-Advertisement-
Play Games

DotBPE.RPC是一款基於dotnet core編寫的RPC框架,而它的爸爸DotBPE,目標是實現一個開箱即用的微服務框架,但是它還差點意思,還僅僅在構思和嘗試的階段。但不管怎麼說RPC是微服務的基礎,先來講講RPC的實現吧。DotBPE.RPC底層通信預設實現基於[DotNetty](htt... ...


0x00 簡介

DotBPE.RPC是一款基於dotnet core編寫的RPC框架,而它的爸爸DotBPE,目標是實現一個開箱即用的微服務框架,但是它還差點意思,還僅僅在構思和嘗試的階段。但不管怎麼說RPC是微服務的基礎,先來講講RPC的實現吧。DotBPE.RPC底層通信預設實現基於DotNetty,這是由微軟Azure團隊開發的C#的Netty實現,非常酷。當然你也可以替換成其他Socket通信組件。DotBPE.RPC使用的預設協議名稱叫Amp,編解碼使用谷歌的Protobuf3,不過這些預設實現都是可以替換的。

源碼地址:https://github.com/xuanye/dotbpe.git

0x01 關於Amp協議和Google Protobuf

Amp(A Message Protocol)

Amp(A Message Protocol) ,中文名叫 一個消息協議 ,是DotBPE.RPC預設實現的消息協議,在實際開發中,其實是不需要瞭解消息是如何編解碼和傳輸的,但是瞭解協議有助於進一步瞭解框架。協議基本結構如下圖所示:

      0        1 2 3 4   5 6 7 8     9     10 11     12 13   <length>-14
+------------+----------+---------+------+-------+---------+------------+
| <ver/argc> | <length> |  <seq>  |<type>|<serId>| <msgid> |   <data>   |
+------------+----------+---------+------+-------+---------+------------+

Amp協議預設消息頭長為14個位元組,不包含擴展包頭
第0位:ver/argc // 為版本號,暫時來說,預設為0
第1-4位: length //為包總長度(含包頭長度)
第5-8位: sequence // 為消息序列號,通過該序列號對應 請求<--->響應
第9位: type // 消息類型,現值有5種,如下:

Request = 1, Response = 2, Notify = 3,NotFound = 4, ERROR = 5
第10-11位: serviceId//消息ID ushort類型
第12-13位: msgId//消息ID ushort類型
在Amp協議中,serviceId標識一類請求,類似應用中的模塊,而msgId標識模塊中的具體方法

其後緊跟實際的數據

Google Protobuf

Google Protocol Buffer( 簡稱 Protobuf) 是 Google 公司內部的混合語言數據標準,目前已經正在使用的有超過 48,162 種報文格式定義和超過 12,183 個 .proto 文件。他們用於 RPC 系統和持續數據存儲系統。

Protocol Buffers 是一種輕便高效的結構化數據存儲格式,可以用於結構化數據串列化,或者說序列化。它很適合做數據存儲或 RPC 數據交換格式。可用於通訊協議、數據存儲等領域的語言無關、平臺無關、可擴展的序列化結構數據格式。目前提供了 多種語言的API,包括C++、 C# 、GO、 JAVA、 PYTHON

我在之前的博客使用CSharp編寫Google Protobuf插件中有過介紹如果通過編寫插件的方式,來通過定義proto文件,並生成我們需要的代碼。

在DotBPE.RPC 中,我使用protobuf來作為服務的描述文件,並通過自定義的插件方式來生成服務端和客戶端代理類。

0x02 快速開始

0. 前提

因為DotBPE是基於dotnet core開發的,你本地必須已經有了dotnet core開發環境
使用github托管代碼,所以你必須已經安裝了git客戶端
需要通過protoc生成模板代碼,所以你必須已經安裝了google protobuf命令行工具

1. 下載示常式序

為了能夠解釋我們的快速開始程式,你需要一份本地能夠運行的示例代碼。從github上下載我已經寫好的示例代碼,可以讓你快速的搭建程式,免去一些繁瑣,但是又必須的步驟。

>$ # Clone the repository to get the example code:    
>$ git clone https://github.com/xuanye/dotbpe-sample.git  
>$ cd dotbpe-sample  

使用VS2017,或者VSCode打開下載好的代碼,目錄結構如下所示:
代碼結構

如果你使用VS2017 可以自動幫你還原,如果使用VSCode的話 ,需要運行dotnet restore 下載依賴,成功後使用dotnet build 編譯一下看看結果:看著很完美
編譯結果

2. 運行程式

運行Server

>$ cd HelloDotBPE.Server   
>$ dotnet run

運行Client

>$ cd HelloDotBPE.Client   
>$ dotnet run

恭喜!已經使用DotBPE.RPC運行一個Server/Client的應用程式。

3. 來一起看一下代碼吧

3.1 服務描述文件proto

首先是DotBPE.RPC框架中對proto的擴展文件,所有的項目都需要這個文件,關於如何擴展proto,我的這篇博客有比較詳細的介紹,這裡就不重覆說了

//dotbpe_option.proto 文件

syntax = "proto3";
package dotbpe;


option csharp_namespace = "DotBPE.ProtoBuf";

import "google/protobuf/descriptor.proto";

//擴展服務
extend google.protobuf.ServiceOptions {
  int32 service_id = 51001;
  bool disable_generic_service_client = 51003; //禁止生成客戶端代碼
  bool disable_generic_service_server = 51004; //禁止生成服務端代碼
}
extend google.protobuf.MethodOptions {
  int32 message_id = 51002;
}

extend google.protobuf.FileOptions {
  bool disable_generic_services_client = 51003; //禁止生成客戶端代碼
  bool disable_generic_services_server = 51004; //禁止生成服務端代碼
  bool generic_markdown_doc = 51005; //是否生成文檔 本示例中無用
  bool generic_objectfactory = 51006; //是否生成objectfactory 本示例中無用
}

下麵的服務描述文件 greeter.proto 才是真正的示例的服務描述文件:比較簡單,定義一個Greeter Rpc服務,並定義一個Hello的方法

//greeter.proto
syntax = "proto3";
package dotbpe;

option csharp_namespace = "HelloDotBPE.Common";

// 引入擴展
import public "dotbpe_option.proto";

// 定義一個服務
service Greeter {
  option (service_id)= 100 ;//消息ID,全局必須唯一
  // Sends a greeting
  rpc Hello (HelloRequest) returns (HelloResponse) {
    option (message_id)= 1 ;//設定消息ID,同一服務內唯一
  }

}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}
// The response message containing the greetings
message HelloResponse {
  string message = 1;
}

通過protoc工具生成模板代碼,示例中的代碼生成到了 HelloDotBPE.Common_g 目錄下,本地可以運行shell命令的同學可以直接到
dotbpe-sample\script\generate 目錄運行sh generate_hello.sh (windows下一般安裝cgywin),不能運行的同學也可以在HelloDotBPE目錄下,直接運行命令行

protoc -I=../protos --csharp_out=./HelloDotBPE.Common/_g/ --dotbpe_out=./HelloDotBPE.Common/_g/   ../protos/dotbpe_option.proto ../protos/greeter.proto  --plugin=protoc-gen-dotbpe=../../tool/protoc_plugin/Protobuf.Gen.exe

當然我還是建議大家安裝以下cgywin運行環境,可以運行unix上的一些常用命令。同時在部署到正式環境的時候可以公用開發環境的一些腳本。

3.2 服務端代碼

服務實現:

// 服務實現代碼
public class GreeterImpl : GreeterBase 
{ 
   public override Task<HelloResponse> HelloAsync(HelloRequest request)
   {
        // 直接返回Hello Name
       return Task.FromResult(new HelloResponse() { Message = "Hello " + request.Name });
   }
}

服務端啟動類

 public class Startup : IStartup
    {
       
        public void Configure(IAppBuilder app, IHostingEnvironment env)
        {
           
        }

        public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            services.AddDotBPE(); // 添加DotBPE.RPC的核心依賴
            services.AddServiceActors<AmpMessage>(actors => {
                actors.Add<GreeterImpl>(); // 註冊服務實現
            });

            return services.BuildServiceProvider();
        }
    }

啟動服務端

   class Program
    {
        static void Main(string[] args)
        {
            Console.OutputEncoding = System.Text.Encoding.UTF8;

            //在控制台輸出調試日誌
            DotBPE.Rpc.Environment.SetLogger(new DotBPE.Rpc.Logging.ConsoleLogger());

            var host = new RpcHostBuilder()
                .UseServer("0.0.0.0:6201") //綁定本地埠6201
                .UseStartup<Startup>()
                .Build();

            host.StartAsync().Wait();

            Console.WriteLine("Press any key to quit!");
            Console.ReadKey();

            host.ShutdownAsync().Wait();

        }
    }

3.3 客戶端代碼

 class Program
    {
        static void Main(string[] args)
        {
            Console.OutputEncoding = Encoding.UTF8;

            var client = AmpClient.Create("127.0.0.1:6201"); //建立鏈接通道
            var greeter = new GreeterClient(client); //客戶端代理類
           
            while (true)
            {
                Console.WriteLine("input your name and press enter:");
                string name = Console.ReadLine();
                if ("bye".Equals(name))
                {
                    break;
                }
                try
                {
                    var request = new HelloRequest() { Name = name };
                    var result = greeter.HelloAsync(request).Result;                  
                    Console.WriteLine($"---------------receive form server:{result.Message}-----------");
                                    
                }
                catch (Exception ex)
                {
                    Console.WriteLine("發生錯誤:" + ex.Message);
                }
            }
            Console.WriteLine($"---------------close connection-----------");
            client.CloseAsync();
        }
    }

0x03 下一步

下一篇 我將詳細講述DotBPE.RPC中的主要類和調用關係,並介紹如何使用DotNetty實現RPC通信。
事實上我正在編寫一個更加複雜的示例https://github.com/xuanye/PiggyMetrics.git
這原是spring cloud的一個示常式序,我使用DotBPE進行改造,用示例描述DotBPE在真實場景中的應用。包括服務註冊和發現,服務間調用,公開HttpApi,監控檢查等功能,並通過實踐進一步完善DotBPE。初步的功能已經實現,不過還沒來的及寫文檔。該系列的後面將詳細描述該系統的實現。


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

-Advertisement-
Play Games
更多相關文章
  • 多個獨立的rtf文件合併時,如果文件紙張方向存在橫向 縱向不一致時,文件之間需要插入分節符 開始文件去掉最後一個"}",中間文件去掉第一個"{"及最後一個"}",最後一個去掉第一個"{";文件如存在紙張方向不一致則需要在兩個文件之間插入分節符。 參考:http://www.aiuxian.com/a ...
  • 系統有些埠是我們平時用不到但是又存在危險的埠,例如139、135、445等埠,windows預設是開著的,這時我們可以手動關閉這些埠!下邊為大家介紹一種通過windows組策略來一次性關閉所有想要關閉的危險埠 系統有些埠是我們平時用不到但是又存在危險的埠,例如139、135、445等端 ...
  • 一.並行LINQ System.Linq名稱空間中包含的類ParallelEnumerable可以分解查詢的工作,使其分佈在多個線程上。 儘管Enumerable類給IEnumerable<T>介面定義了擴展方法,但ParallelEnumerable類的大多數擴展方法是ParallerQuery< ...
  • 原文鏈接:http://blog.csdn.net/hebbers/article/details/70332015 關鍵點在與 ...
  • 經常在項目中遇到定時任務的時候,通常第一個想到的是Timer定時器,但是這玩意功能太弱雞,實際上通常採用的是專業化的第三方調度框架,比如說 Quartz,它具有功能強大和應用的靈活性,我想使用過的人都非常瞭解,那麼本篇就來說說如何通過代碼和配置文件來進行job和trigger的配置。 一:常規的jo ...
  • 今天學習angularjs向資料庫添加數據。學習此篇,得從以往幾篇開始,因為那還有創建數據表等演示。現在來創建一個添加的存儲過程: SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE PROCEDURE [dbo].[usp_Goods_I ...
  • c 介面使用詳解 c 中介面隱式與顯示實現 c 中介面可以隱式實現、顯示實現,隱式實現更常使用、顯示實現較少使用 其區別在於 1. 顯示實現避免介面函數簽名衝突 2. 顯示實現只可以以介面形式調用 3. 顯示實現其子類需無法繼承介面 4. 隱式實現可以撕裂調用、可以介面調用 5. 隱式實現其子類可以 ...
  • 下載並引入兩個dll文件 NPinyin.dll 和 ChnCharInfo.dll 其實這兩個dll 任何一個都可以實現漢字轉拼音,然而 NPinyin.dll 收錄的漢字並不全,但是很人性化,能識別一些常用的漢字。ChnCharInfo.dll 是微軟的很全但是不人性化。另外本套代碼外有一個自己 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...