RPC远程过程调用,二进制封装,提供高吞吐低延迟的高性能RPC框架
大石头 authored at 2022-08-10 13:26:19
9.78 KiB
NewLife.Remoting
# Api¿Í»§¶ËʹÓÃÊÖ²á ±¾Îĵµ½éÉÜ NewLife.Remoting ÖÐÓ¦Óÿͻ§¶Ë»ùÀà `ClientBase` µÄʹÓ÷½·¨£¬ÊÊÓÃÓÚÉ豸½ÓÈë¡¢Ó¦ÓöԽӵȳ¡¾°¡£ --- ## 1. ¸ÅÊö `ClientBase` ÊÇÓ¦Óÿͻ§¶ËµÄ³éÏó»ùÀ࣬ʵÏÖÁ˶ԽÓÄ¿±êƽ̨µÄµÇ¼¡¢ÐÄÌø¡¢¸üкÍÖ¸ÁîÏ·¢µÈ³¡¾°²Ù×÷¡£ ### 1.1 µäÐÍÓ¦Óüܹ¹ | ¼Ü¹¹ | ЭÒé | ˵Ã÷ | ʾÀý | |------|------|------|------| | **RPCÓ¦Óüܹ¹** | TCP/UDP | ¿Í»§¶Ëͨ¹ý ApiClient Á¬½Ó·þÎñ¶Ë ApiServer£¬·þÎñ¶ËÖ±½ÓÏ·¢Ö¸Áî | ÂìÒϵ÷¶È | | **HTTPÓ¦Óüܹ¹** | HTTP/HTTPS | ¿Í»§¶Ëͨ¹ý ApiHttpClient Á¬½Ó WebApi£¬·þÎñ¶Ëͨ¹ý WebSocket Ï·¢Ö¸Áî | ZeroIot É豸½ÓÈë | | **OAuthÓ¦Óüܹ¹** | HTTP/HTTPS | ¿Í»§¶Ëͨ¹ý OAuth µÇ¼»ñÈ¡ÁîÅÆ£¬ºóÐøÇëÇóЯ´øÁîÅÆ | Ðdz¾ AppClient | ### 1.2 ºËÐŦÄÜ - **µÇ¼ÈÏÖ¤**£ºÊ¹ÓñàÂëºÍÃÜÔ¿µÇ¼·þÎñ¶Ë£¬»ñÈ¡ÁîÅÆ - **ÐÄÌø±£»î**£º¶¨Ê±Éϱ¨¿Í»§¶ËÐÔÄÜÊý¾Ý£¬Î¬³ÖÔÚÏß״̬ - **×Ô¶¯¸üÐÂ**£º¼ì²â²¢ÏÂÔØ¸üаü£¬×Ô¶¯Éý¼¶Ó¦Óà - **ÃüÁîÏ·¢**£º½ÓÊÕ²¢Ö´ÐзþÎñ¶ËÏ·¢µÄÃüÁî - **ʼþÉϱ¨**£ºÏò·þÎñ¶ËÍÆË͸÷ÀàʼþÐÅÏ¢ --- ## 2. ¿ìËÙ¿ªÊ¼ ### 2.1 ´´½¨×Ô¶¨Òå¿Í»§¶Ë ¼Ì³Ð `ClientBase` ²¢ÊµÏÖÒµÎñÂß¼­£º ```csharp public class MyDeviceClient : ClientBase { public MyDeviceClient() : base() { // ÉèÖýӿÚ·¾¶Ç°×º SetActions("Device/"); // ÆôÓù¦ÄÜÌØÐÔ Features = Features.Login | Features.Logout | Features.Ping | Features.Notify; } public MyDeviceClient(IClientSetting setting) : base(setting) { SetActions("Device/"); Features = Features.Login | Features.Logout | Features.Ping | Features.Notify; } } ``` ### 2.2 ÅäÖÿͻ§¶Ë ```csharp var client = new MyDeviceClient { Server = "http://localhost:5000", // ·þÎñ¶ËµØÖ· Code = "device001", // É豸±àÂë Secret = "your_secret_key", // É豸ÃÜÔ¿ Timeout = 15_000, // ³¬Ê±Ê±¼ä£¨ºÁÃ룩 Log = XTrace.Log, // ÈÕÖ¾Êä³ö }; ``` ### 2.3 Æô¶¯¿Í»§¶Ë ```csharp // ·½Ê½Ò»£ºÒì²½´ò¿ª£¨ÍƼö£© // ÔÚÍøÂçδ¾ÍÐ÷֮ǰ»á·´¸´³¢ÊԵǼ client.Open(); // ·½Ê½¶þ£ºÖ±½ÓµÇ¼ await client.Login("MyApp"); ``` ### 2.4 ¹Ø±Õ¿Í»§¶Ë ```csharp // ×¢Ïú²¢ÊÍ·Å×ÊÔ´ await client.Logout("Ó¦ÓùرÕ"); client.Dispose(); // »òÖ±½Ó Dispose£¨»á×Ô¶¯×¢Ïú£© client.Dispose(); ``` --- ## 3. ¹¦ÄÜÌØÐÔ Í¨¹ý `Features` ö¾Ù¿ØÖƿͻ§¶Ë¹¦ÄÜ£º | ÌØÐÔ | ˵Ã÷ | |------|------| | `Login` | µÇ¼¹¦ÄÜ | | `Logout` | ×¢Ïú¹¦ÄÜ | | `Ping` | ÐÄÌø¹¦ÄÜ | | `Upgrade` | ×Ô¶¯¸üй¦ÄÜ | | `Notify` | ÏÂÐÐ֪ͨ£¨WebSocket³¤Á¬½Ó£© | | `CommandReply` | ÃüÁîÏìÓ¦Éϱ¨ | | `PostEvent` | ʼþÉϱ¨¹¦ÄÜ | | `All` | ÆôÓÃÈ«²¿¹¦ÄÜ | ```csharp // ÆôÓöà¸ö¹¦ÄÜ client.Features = Features.Login | Features.Logout | Features.Ping | Features.Notify; // ÆôÓÃÈ«²¿¹¦ÄÜ client.Features = Features.All; ``` --- ## 4. µÇ¼ÓëÈÏÖ¤ ### 4.1 »ù±¾µÇ¼ ```csharp // µÇ¼²¢»ñÈ¡ÏìÓ¦ var response = await client.Login("À´Ô´±êʶ"); if (client.Logined) { Console.WriteLine($"µÇ¼³É¹¦£¬ÁîÅÆ£º{response?.Token}"); } ``` ### 4.2 ×Ô¶¨ÒåµÇ¼ÇëÇó ÖØÐ´ `BuildLoginRequest` ·½·¨Ìí¼Ó×Ô¶¨Òå²ÎÊý£º ```csharp public class MyDeviceClient : ClientBase { public String ProductKey { get; set; } public override ILoginRequest BuildLoginRequest() { var request = base.BuildLoginRequest(); // Ìí¼Ó×Ô¶¨Òå²ÎÊý if (request is MyLoginRequest myRequest) { myRequest.ProductKey = ProductKey; } return request; } } ``` ### 4.3 µÇ¼³É¹¦Ê¼þ ```csharp client.OnLogined += (sender, e) => { var request = e.Request; var response = e.Response; Console.WriteLine($"µÇ¼³É¹¦£º{response.Code}"); // ´¦Àí·þÎñ¶ËÏ·¢µÄ±àÂëºÍÃÜÔ¿£¨×Ô¶¯×¢²á³¡¾°£© if (!response.Code.IsNullOrEmpty()) { // ±£´æÐµıàÂëºÍÃÜÔ¿ } }; ``` ### 4.4 ÃÜÂë±£»¤ ʹÓà `IPasswordProvider` ±£»¤ÃÜÂë´«Ê䣺 ```csharp client.PasswordProvider = new SaltPasswordProvider { Algorithm = "md5", SaltTime = 60 }; ``` --- ## 5. ÐÄÌøÓë±£»î ### 5.1 ×Ô¶¯ÐÄÌø µÇ¼³É¹¦ºó£¬¿Í»§¶Ë»á×Ô¶¯Æô¶¯ÐÄÌø¶¨Ê±Æ÷£¬Ä¬Èϼä¸ô 60 Ãë¡£ ### 5.2 ÊÖ¶¯ÐÄÌø ```csharp var response = await client.Ping(); if (response != null) { Console.WriteLine($"ÐÄÌø³É¹¦£¬·þÎñÆ÷ʱ¼äÆ«ÒÆ£º{client.Span}"); } ``` ### 5.3 ×Ô¶¨ÒåÐÄÌøÊý¾Ý ÖØÐ´ `BuildPingRequest` »ò `FillPingRequest` Ìí¼Ó×Ô¶¨ÒåÊý¾Ý£º ```csharp public override IPingRequest BuildPingRequest() { var request = base.BuildPingRequest(); // Ìí¼Ó×Ô¶¨ÒåÊý¾Ý if (request is MyPingRequest myRequest) { myRequest.CustomData = GetCustomData(); } return request; } ``` ### 5.4 ÐÄÌøÊý¾Ý˵Ã÷ ĬÈÏÐÄÌø»áÉϱ¨ÒÔÏÂÐÔÄÜÊý¾Ý£º | ×Ö¶Î | ˵Ã÷ | |------|------| | `Memory` | ÄÚ´æ´óС | | `AvailableMemory` | ¿ÉÓÃÄÚ´æ | | `CpuRate` | CPU Õ¼ÓÃÂÊ | | `Temperature` | ÎÂ¶È | | `Battery` | µçÁ¿ | | `TotalSize` | ´ÅÅÌ´óС | | `AvailableFreeSpace` | ´ÅÅÌ¿ÉÓÿռä | | `IP` | ±¾µØ IP µØÖ· | | `Uptime` | ÔËÐÐʱ¼ä£¨Ã룩 | | `Delay` | ÍøÂçÑÓ³Ù£¨ºÁÃ룩 | --- ## 6. ÃüÁî´¦Àí ### 6.1 ×¢²áÃüÁî´¦ÀíÆ÷ ```csharp // ·½Ê½Ò»£º¼òµ¥×Ö·û´®²ÎÊý client.RegisterCommand("Reboot", (String? args) => { Console.WriteLine($"ÊÕµ½ÖØÆôÃüÁ{args}"); return "ÖØÆô³É¹¦"; }); // ·½Ê½¶þ£ºÒì²½´¦Àí client.RegisterCommand("UpdateConfig", async (String? args) => { await UpdateConfigAsync(args); return "ÅäÖøüгɹ¦"; }); // ·½Ê½Èý£ºÍêÕûÃüÁîÄ£ÐÍ client.RegisterCommand("Execute", (CommandModel model) => { return new CommandReplyModel { Id = model.Id, Status = CommandStatus.ÒÑÍê³É, Data = "Ö´Ðгɹ¦" }; }); // ·½Ê½ËÄ£ºÒì²½ + È¡ÏûÁîÅÆ client.RegisterCommand("LongTask", async (CommandModel model, CancellationToken ct) => { await DoLongTaskAsync(model.Argument, ct); return new CommandReplyModel { Id = model.Id, Status = CommandStatus.ÒÑÍê³É }; }); ``` ### 6.2 ÃüÁîʼþ ```csharp client.Received += (sender, e) => { var model = e.Model; Console.WriteLine($"ÊÕµ½ÃüÁ{model.Command}£¬²ÎÊý£º{model.Argument}"); // ¿ÉÒÔÐÞ¸ÄÃüÁî»òÉèÖÃ×Ô¶¨ÒåÏìÓ¦ e.Reply = new CommandReplyModel { Id = model.Id, Status = CommandStatus.ÒÑÍê³É, Data = "´¦ÀíÍê³É" }; }; ``` ### 6.3 Ö÷¶¯·¢ËÍÃüÁî ```csharp // ÏòÃüÁîÒýÇæ·¢ËÍÃüÁ´¥·¢ÒÑ×¢²áµÄ´¦ÀíÆ÷ var reply = await client.SendCommand("Reboot", "Á¢¼´ÖØÆô"); ``` ### 6.4 ÃüÁî״̬ | ״̬ | ˵Ã÷ | |------|------| | `¾ÍÐ÷` | µÈ´ýÖ´ÐÐ | | `´¦ÀíÖÐ` | ÕýÔÚÖ´ÐÐ | | `ÒÑÍê³É` | Ö´Ðгɹ¦ | | `´íÎó` | Ö´ÐÐʧ°Ü | | `È¡Ïû` | ÒÑÈ¡Ïû | --- ## 7. ʼþÉϱ¨ ### 7.1 Éϱ¨Ê¼þ ```csharp // Éϱ¨ÐÅϢʼþ client.WriteInfoEvent("DeviceStart", "É豸Æô¶¯³É¹¦"); // Éϱ¨´íÎóʼþ client.WriteErrorEvent("SensorError", "ζȴ«¸ÐÆ÷Òì³£"); // Éϱ¨×Ô¶¨ÒåÀàÐÍʼþ client.WriteEvent("alert", "HighTemperature", "ζȳ¬¹ýãÐÖµ£º85¡ãC"); ``` ### 7.2 ʼþÀàÐÍ | ÀàÐÍ | ˵Ã÷ | |------|------| | `info` | ÐÅϢʼþ | | `alert` | ¸æ¾¯Ê¼þ | | `error` | ´íÎóʼþ | ### 7.3 ÅúÁ¿Éϱ¨ ʼþ»á×Ô¶¯»º´æ²¢ÅúÁ¿Éϱ¨£¬Ä¬Èϼä¸ô 60 Ã룬ÿÅú×î¶à 100 Ìõ¡£ ```csharp // Ö±½ÓÅúÁ¿Éϱ¨ await client.PostEvents(new EventModel[] { new() { Type = "info", Name = "Event1", Remark = "ʼþ1" }, new() { Type = "info", Name = "Event2", Remark = "ʼþ2" }, }); ``` --- ## 8. ×Ô¶¯¸üР### 8.1 ÆôÓøüй¦ÄÜ ```csharp client.Features |= Features.Upgrade; ``` ### 8.2 ÊÖ¶¯¼ì²é¸üР```csharp var info = await client.Upgrade("stable"); // Ö¸¶¨¸üÐÂͨµÀ if (info != null) { Console.WriteLine($"·¢ÏÖа汾£º{info.Version}"); } ``` ### 8.3 ¸üÐÂÁ÷³Ì 1. µ÷Ó÷þÎñ¶Ë½Ó¿Ú²éѯ¸üÐÂÐÅÏ¢ 2. ÏÂÔØ¸üаü 3. УÑéÎļþ¹þÏ£ 4. ½âѹ²¢¸²¸ÇÎļþ 5. Ö´ÐÐÔ¤°²×°½Å±¾£¨¿ÉÑ¡£© 6. Ç¿ÖÆ¸üÐÂʱ×Ô¶¯ÖØÆô --- ## 9. Ô¶³Ìµ÷Óà ### 9.1 µ÷Ó÷þÎñ¶Ë½Ó¿Ú ```csharp // Òì²½µ÷Óà var result = await client.InvokeAsync<MyResponse>("Device/GetInfo", new { id = 123 }); // ͬ²½µ÷Óà var result = client.Invoke<MyResponse>("Device/GetInfo", new { id = 123 }); // GET ÇëÇ󣨽ö HTTP£© var result = await client.GetAsync<MyResponse>("Device/GetStatus", new { id = 123 }); ``` ### 9.2 ×Ô¶¯ÖØÐµÇ¼ µ±ÁîÅÆ¹ýÆÚ£¨·þÎñ¶Ë·µ»Ø 401£©Ê±£¬¿Í»§¶Ë»á×Ô¶¯ÖØÐµÇ¼²¢ÖØÊÔÇëÇó¡£ --- ## 10. ʱ¼äͬ²½ ¿Í»§¶Ë»á×Ô¶¯¼ÆËãÓë·þÎñÆ÷µÄʱ¼ä²î£¬Í¨¹ý `GetNow()` »ñȡУ׼ºóµÄʱ¼ä£º ```csharp // »ñÈ¡»ùÓÚ·þÎñÆ÷µÄµ±Ç°Ê±¼ä var serverTime = client.GetNow(); // ʱ¼ä²î£¨·þÎñÆ÷ʱ¼ä - ¿Í»§¶Ëʱ¼ä£© var span = client.Span; // ÍøÂçÑÓ³Ù£¨ºÁÃ룩 var delay = client.Delay; ``` --- ## 11. ÈÕÖ¾Óë×·×Ù ### 11.1 ÅäÖÃÈÕÖ¾ ```csharp client.Log = XTrace.Log; ``` ### 11.2 Á´Â·×·×Ù ```csharp client.Tracer = new DefaultTracer(); ``` --- ## 12. ¿Í»§¶ËÉèÖà ʵÏÖ `IClientSetting` ½Ó¿Ú³Ö¾Ã»¯ÅäÖ㺠```csharp public class DeviceSetting : IClientSetting { public String Server { get; set; } = "http://localhost:5000"; public String Code { get; set; } = ""; public String? Secret { get; set; } public void Save() { // ±£´æµ½Îļþ»òÊý¾Ý¿â File.WriteAllText("config.json", this.ToJson()); } } ``` ʹÓÃÉèÖ㺠```csharp var setting = new DeviceSetting { Server = "http://localhost:5000" }; var client = new MyDeviceClient(setting); ``` --- ## 13. ¸ß¼¶Ó÷¨ ### 13.1 ×Ô¶¨Òå½Ó¿Ú·¾¶ ```csharp protected override void SetActions(String prefix) { base.SetActions(prefix); // Ìí¼Ó×Ô¶¨Òå½Ó¿Ú Actions[MyFeatures.CustomAction] = prefix + "CustomAction"; } ``` ### 13.2 ×Ô¶¨Òå HTTP ¿Í»§¶Ë ```csharp protected override ApiHttpClient CreateHttp(String urls) { var http = base.CreateHttp(urls); // ×Ô¶¨ÒåÅäÖà http.Timeout = 30_000; http.DefaultUserAgent = "MyApp/1.0"; return http; } ``` ### 13.3 WebSocket ³¤Á¬½Ó ÆôÓà `Notify` ÌØÐԺ󣬿ͻ§¶Ë»á×Ô¶¯½¨Á¢ WebSocket ³¤Á¬½Ó½ÓÊÕ·þÎñ¶ËÍÆËÍ£º ```csharp client.Features |= Features.Notify; ``` --- ## 14. ×î¼Ñʵ¼ù 1. **ʹÓÃÒÀÀµ×¢Èë**£ºÔÚ ASP.NET Core ÖÐ×¢²áΪµ¥Àý·þÎñ 2. **ÅäÖó־û¯**£ºÊµÏÖ `IClientSetting` ±£´æ×Ô¶¯×¢²áµÄ±àÂëºÍÃÜÔ¿ 3. **ÈÕÖ¾×·×Ù**£ºÅäÖà `Log` ºÍ `Tracer` ±ãÓÚÎÊÌâÅŲé 4. **ÓÅÑŹرÕ**£ºµ÷Óà `Dispose()` È·±£ÕýÈ·×¢ÏúºÍÊÍ·Å×ÊÔ´ 5. **ÃüÁîÃݵÈ**£ºÃüÁî´¦ÀíÆ÷Ó¦Ö§³ÖÖØ¸´Ö´ÐÐ 6. **Òì³£´¦Àí**£º²¶»ñ `ApiException` ´¦ÀíÒµÎñÒì³£ --- ## 15. ʾÀýÏîÄ¿ ²Î¿¼ `Samples` Ŀ¼ÏµÄʾÀýÏîÄ¿£º - **IoTZero**£ºÎïÁªÍøÉ豸½ÓÈëʾÀý - **Demo**£º»ù´¡¹¦ÄÜÑÝʾ - **Zero.Desktop**£º×ÀÃæÓ¦ÓÃʾÀý - **ZeroServer**£º·þÎñ¶ËʾÀý --- £¨Í꣩