.NET 开源项目 StreamJsonRpc 介绍[中篇]
閱讀本文大概需要 11 分鐘。
上一篇介紹了一些預備知識,包括 JSON-RPC 介紹和實現了 JSON-RPC 的 StreamJsonRpc 介紹,講到了 StreamJsonRpc 可以通過 .NET 的 Stream 類和 WebSocket 類實現 JSON-RPC 協議的通信。本篇就先選擇其中的 Stream 類來講解,通過具體的示例講解如何使用 StreamJsonRpc 實現 RPC 調用。
準備工作
先新建兩個 Console 應用,分別命名為 StreamSample.Client 和 StreamSample.Server,并均添加 StreamJsonRpc 包引用。
mkdir StreamJsonRpcSamples # 創建目錄 cd StreamJsonRpcSamples # 進入目錄 dotnet new sln -n StreamJsonRpcSamples # 新建解決方案 dotnet new console -n StreamSample.Client # 建新客戶端應用 dotnet new console -n StreamSample.Server # 新建服務端應用 dotnet sln add StreamSample.Client StreamSample.Server # 將應用添加到解決方案 dotnet add StreamSample.Client package StreamJsonRpc # 為客戶端安裝 StreamJsonRpc 包 dotnet add StreamSample.Server package StreamJsonRpc # 為服務端安裝 StreamJsonRpc 包上篇?提到了實現 JSON-RPC 通訊要經歷四個步驟:建立連接、發送請求、接收請求、斷開連接,其中發送請求和接收請求可以歸為數據通訊,下面按照這幾個步驟順序來逐步講解。
建立連接
使用 Stream 實現 JSON-RPC 協議的通訊,要求該 Stream 必須是一個全雙工 Stream(可同時接收數據和發送數據)或才是一對半雙工 Stream(本文不作討論)。實現了全雙工的 Stream 類在 .NET 中有?PipeStream、NetworkStream?等,本示例用的是?NamedPipeClientStream?類和?NamedPipeServerStream,前者用于客戶端,后者用于服務端。
先看服務端代碼示例:
int clientId = 1;var stream = new NamedPipeServerStream("StringJsonRpc",PipeDirection.InOut,NamedPipeServerStream.MaxAllowedServerInstances,PipeTransmissionMode.Byte,PipeOptions.Asynchronous);Console.WriteLine("等待客戶端連接..."); await stream.WaitForConnectionAsync(); Console.WriteLine($"已與客戶端 #{clientId} 建立連接");這里使用了?NamedPipeServerStream?類,其第一個構造參數指定了該 Stream 管道的名稱,方便客戶端使用該名稱查找。其它參數就不解釋了,其各自的含義可以在你編寫代碼時通過智能提示了解。
Stream 實例通過?WaitForConnectionAsync?來等待一個客戶端連接。由于該服務端可以連接多個客戶端,這里使用自增長的?clientId?來標識區分它們。
再來看客戶端代碼示例:
var stream = new NamedPipeClientStream(".","StringJsonRpc",PipeDirection.InOut,PipeOptions.Asynchronous);Console.WriteLine("正在連接服務器..."); await stream.ConnectAsync(); Console.WriteLine("已建立連接!");和服務器類似,客戶端使用的是?NamedPipeClientStream?類來建立連接,在其構造參數中需要指定服務端的地址(這里用了.代表本機)和通訊管道的名稱。Stream 實例通過?ConnectAsync?方法主動向服務器請求連接。
如果網絡是通的,客戶端和服務端就能成功建立連接。下面就要實現客戶端和服務端之間的數據通訊了,即客戶端發送請求和服務端接收并處理請求。
數據通訊
客戶端與服務端建立連接后,數據不會無緣無故從一端流到另一端,要實現兩端的數據通訊還需要先把通訊管道架設起來,在其兩端設定對應的控制和處理程序。工程上這個聽起來好像不簡單,但對于 StreamJsonRpc 來說是件非常簡單的事。最簡單的方法是使用 JsonRpc 類的?Attach?靜態方法來架設兩端的 Stream 管道,該方法返回一個 JsonRpc 實例可以用來控制數據的通訊。
對于服務端,架設管道的同時還要為管道上的請求添加監聽和對應的處理程序,比如定義一個名為?GreeterServer?的類來處理“打招呼”的請求:
public?class?GreeterServer {public?string?SayHello(string name){Console.WriteLine($"收到【{name}】的問好,并回復了他");return?$"您好,{name}!";} }然后實例化該類,把它傳給 JsonRpc 類的?Attach?靜態方法:
static?async Task Main(string[] args) {..._ = ResponseAsync(stream, clientId);clientId++; }static Task ResponseAsync(NamedPipeServerStream stream, int clientId) {var jsonRpc = JsonRpc.Attach(stream, new GreeterServer());return jsonRpc.Completion; }這里我們單獨定義了一個?ResponseAsync?方法用來處理客戶端請求,在?Main?函數中我們不用關心該方法返回的 Task 任務,所以使用了棄元。
對于客戶端也是類似的,使用 JsonRpc 類的?Attach?靜態方法來完成管道架設,并調用 JsonRpc 實例的?InvokeAsync?方法向服務端發送指定請求。代碼示例如下:
... Console.WriteLine("我是精致碼農,開始向服務端問好..."); var jsonRpc = JsonRpc.Attach(stream); var message = await jsonRpc.InvokeAsync<string>("SayHello", "精致碼農"); Console.WriteLine($"來自服務端的響應:{message}");這樣就實現了客戶端調用服務端的方法,但客戶端需要知道服務端的方法簽名。這里只是為示例演示,在實際情況中,客戶端和服務端需要先約定好接口,這樣客戶端就可以面向接口實現強類型編程,不必關心服務端處理程序的具體信息。
注意到沒,從建立連接到實現數據通訊,客戶端和服務端都是對應的,而且使用的類和方法都是相似的。
斷開連接
當客戶端或服務器端在不需要發送請求或響應請求時,則可以調用 JsonRpc 實例的 Dispose 方法斷開并釋放連接。
jsonRpc.Dispose();如果需要斷開連接,一般是由客戶端這邊發起,比如對于控制臺應用按 Ctrl + C 結束任務便會斷開與服務端的連接。那服務端如何知道某個客戶端斷開了連接呢?可以手動等待 JsonRpc 實例的 Completion 任務完成,比如:
static?async Task ResponseAsync(NamedPipeServerStream stream, int clientId) {var jsonRpc = JsonRpc.Attach(stream, new GreeterServer());await jsonRpc.Completion;Console.WriteLine($"客戶端 #{clientId} 的已斷開連接");jsonRpc.Dispose();await stream.DisposeAsync(); }這里為了保險起見,我還手動把 stream 也釋放掉了。
除了主動斷開連接,客戶端或服務器拋出未 catch 的異常也會致使連接中斷,在實際情況中針對這種異常的連接中斷可能需要編寫重試機制,這里就不展開討論了。
完整代碼
以上為了講解方便,代碼只貼了與上下文相關的部分,最后我再把完整代碼貼一下吧。
服務端 StreamSample.Server 下的 Program.cs:
客戶端 StreamSample.Client 下的 Program.cs:
完整代碼已放到 GitHub,地址為:
github.com/liamwang/StreamJsonRpcSamples
兩個客戶端和服務端一起運行的截圖:
本篇總結
本文通過一個簡單但完整的示例講解了如何使用 StreamJsonRpc 來實現基于 JSON-RPC 協議的 RPC 調用。由于服務端和客戶端都使用的是 StreamJsonRpc 庫來實現的,所以在示例中感覺不到 JSON-RPC 協議帶來的統一規范,也沒看到具體的 JSON 格式的數據。這是因為 StreamJsonRpc 庫都已經幫我們封裝好了,兩端都基于 C#,示例使用的也是簡單的 Stream 方式,隱藏了我們不必關心的細節。其實只要符合 JSON-RPC 協議標準,C# 寫的服務端也可以由其它語言實現的客戶端來調用,反之亦然。
關注我一段時間的朋友都知道,我的文章篇幅一般不會太長,主要是方便大家利用零碎時間把它一次性看完。StreamJsonRpc 的使用遠不止本文講的這些,比如還有基于 WebSocket 進行數據傳輸的方式。來想通過兩篇講完,但講了一半就已經超出了預期的篇幅長度。所以我把本文定為[中篇],如果有時間我會繼續寫[下篇],下篇主要會講 StreamJsonRpc + WebSocket 的使用,并會盡量以更貼合實際應用場景的示例來講解。
總結
以上是生活随笔為你收集整理的.NET 开源项目 StreamJsonRpc 介绍[中篇]的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【复杂系统迁移 .NET Core平台系
- 下一篇: asp.net ajax控件工具集 Au