亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

c# RPC框架的使用簡介

 更新時間:2021年02月07日 11:00:37   作者:Supper_litt  
這篇文章主要介紹了c# RPC框架的使用簡介,幫助大家更好的理解和使用c#,感興趣的朋友可以了解下

寫在前面:

  RPC,聽過很有段時間了,但是一直都不太清楚是干嘛的,今天我們來捋一捋。

解釋:

  【Remote Procedure Call Protocol】遠(yuǎn)程過程調(diào)用(就是說,A程序要調(diào)用一個b方法,然而這個b方法的實現(xiàn)在B程序內(nèi)部,B程序還可能和A不在一個電腦上面,怎么調(diào)用?http可以調(diào)用/rpc也可以,讓他像調(diào)用本地方法一樣調(diào)用)

使用初探:

  用了一下市面上的,rpc框架,步驟如下:

  1、寫一個基本的代碼,告訴有哪些方法。

  2、然后服務(wù)端集成,

  3、客戶端集成,

  4、OK調(diào)用生效了。

  感覺有點像TCP在傳輸數(shù)據(jù),從A服務(wù)器傳遞,傳遞類名,方法名,參數(shù),值,然后B服務(wù)器拿到數(shù)據(jù),計算結(jié)果,然后把數(shù)據(jù)在回傳給A。。。這樣理解一下的話,就很簡單了。

     下面動手寫一個吧。

自己動手:

  服務(wù)端:

  既然服務(wù)端是實現(xiàn)的地方,我們寫一個算是實現(xiàn)類的方法試試:寫了一個接口和一個實現(xiàn),為了演示效果,寫了兩個方法。

public interface IMyTestService
  {
    int calc(int x, int y);

    bool login(string name, string pwd);
  }

  public class MyTestServiceImpl : IMyTestService
  {
    public int calc(int x, int y)
    {
      return x + y;
    }

    public bool login(string name, string pwd)
    {
      if (name == "test" && pwd == "123456")
      {
        return true;
      }

      return false;
    }
  }

  OK,服務(wù)端的大部分完成了。

  然后就是TCP服務(wù)器,TCP服務(wù)器對大家來說,就太簡單不過了,不就是創(chuàng)建一個Socket對象,綁定一個端口,獲取客戶端請求的Socket對象,然后和他交互么。沒啥多說的。

class Program
  {
    static void Main(string[] args)
    {
      Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
      server.Bind(new IPEndPoint(IPAddress.Any, 10000));
      server.Listen(1000);

      Thread t = new Thread(Execute);
      t.IsBackground = true;
      t.Start(server);

      Console.WriteLine("rpc服務(wù)器已啟動");
      Console.ReadLine();
    }

    private static void Execute(Object obj)
    {
      Socket server = obj as Socket;
      while (true)
      {
        Socket client = server.Accept();

        Thread t = new Thread(SingleExecute);
        t.IsBackground = true;
        t.Start(client);
      }
    }

    private static void SingleExecute(object obj)
    {
      // 讀取 
      Socket client = obj as Socket;

      byte[] buffer = new byte[8192];
      int count = client.Receive(buffer);
      if (count > 0)
      {
        var data = ServiceHelpercs.Handle(buffer);
        client.Send(data);
      }

      client.Shutdown(SocketShutdown.Both);
    }
  }

  我們假定,所有的客戶端數(shù)據(jù),可以在一個請求包里面解析掉,因為如果一次的數(shù)據(jù)接收不能解析,那就還要添加一個大小了,客戶端要告訴我你給我了多少消息,然后我再讀取指定數(shù)據(jù),拿到所有的內(nèi)容

  這里創(chuàng)建,一個ServiceHelpers來幫助對,真實算法的調(diào)用。如下:

public class ServiceHelpercs
  {
    public static byte[] Handle(byte[] buffer)
    {
      MemoryStream ms = new MemoryStream(buffer);
      BinaryReader br = new BinaryReader(ms);

      int inter_len = br.ReadByte();
      string inter_name = Encoding.UTF8.GetString(br.ReadBytes(inter_len));

      int method_len = br.ReadByte();
      string method_name = Encoding.UTF8.GetString(br.ReadBytes(method_len));

      int args_length = br.ReadByte();
      int return_type = br.ReadByte();

      List<object> list = new List<object>();
      for (int i = 0; i < args_length; i++)
      {          // 0:void 忽略 1:int 2:bool 3:string
        int arg_type = br.ReadByte();
        if (arg_type == 1)
        {
          byte[] values = br.ReadBytes(4);
          list.Add(bytes2int(values));
        }
        else if (arg_type == 2)
        {
          bool value = br.ReadByte() == 1;
          list.Add(value);
        }
        else if (arg_type == 3)
        {
          int str_len = bytes2int(br.ReadBytes(4));
          string str = Encoding.UTF8.GetString(br.ReadBytes(str_len));
          list.Add(str);
        }
      }

      Type inter_type = null;
      var types = Assembly.GetExecutingAssembly().GetTypes();
      foreach (var type in types)
      {
        var ts = type.GetInterfaces();
        foreach (var t in ts)
        {
          if (t.Name == inter_name)
          {
            inter_type = type;
            break;
          }
        }
      }

      MethodInfo invokeMethod = null;
      if (inter_type != null)
      {
        var methods = inter_type.GetMethods();
        foreach (var method in methods)
        {
          if (method.Name == method_name)
          {
            invokeMethod = method;
            break;
          }
        }
      }

      if (invokeMethod != null)
      {
        Object thisObj = Activator.CreateInstance(inter_type);
        object result = invokeMethod.Invoke(thisObj, list.ToArray());
        if (return_type == 1)
        {
          int value = Convert.ToInt32(result);

          return int2bytes(value);
        }
        else if (return_type == 2)
        {
          return new byte[1] { Convert.ToBoolean(result) ? (byte)1 : (byte)0 };
        }
        else if (return_type == 2)
        {
          List<byte> result_data = new List<byte>();
          var str = (result == null ? "" : result.ToString());
          var data = Encoding.UTF8.GetBytes(str);

          result_data.AddRange(int2bytes(data.Length));
          result_data.AddRange(data);

          return result_data.ToArray();
        }
      }

      return new byte[1] { 0xFF };
    }

    public static byte[] int2bytes(int len)
    {
      byte[] data_len = new byte[4];
      data_len[0] = (byte)((len >> 8 * 3) & 0xFF);
      data_len[1] = (byte)((len >> 8 * 2) & 0xFF);
      data_len[2] = (byte)((len >> 8 * 1) & 0xFF);
      data_len[3] = (byte)(len & 0xFF);

      return data_len;
    }

    public static int bytes2int(byte[] buffer)
    {
      int value = 0;
      value += (int)(buffer[0] << (8 * 3));
      value += (int)(buffer[1] << (8 * 2));
      value += (int)(buffer[2] << (8 * 1));
      value += (int)(buffer[3]);

      return value;
    }
  }

  解析的類很簡單,因為這里創(chuàng)建的數(shù)據(jù)結(jié)構(gòu)很簡單。

  按照我們的約定,這里,對數(shù)據(jù)按照我定義的方式來進(jìn)行解包即可。

  服務(wù)器就完成了,是不是很簡單。當(dāng)然客戶端也需要按照一樣的方式處理打包即可

  客戶端:

  客戶端就很簡單了,只需要連接到服務(wù)器,通過我們自動生成的代碼(這里沒有寫自動生成,就手動了),然后就直接可以返回結(jié)果了

class Program
  {
    static void Main(string[] args)
    {
      IMyService service = new MyServiceProxy();
      DateTime startTime = DateTime.Now;
      int result = service.add(123, 321);

      int min_seconds = (int)(DateTime.Now - startTime).TotalMilliseconds;

      Console.WriteLine(result + " 耗時 " + min_seconds);
      Console.ReadLine();
    }
  }

  上面直接調(diào)用了,接口,至于接口的實現(xiàn),這里的步驟就三個:1、構(gòu)造需要請求的數(shù)據(jù),2、連接服務(wù)器并發(fā)送數(shù)據(jù),3、接收返回內(nèi)容,并解析結(jié)果。

public class MyServiceProxy : IMyService
  {
    public int add(int x, int y)
    {
      List<ArgInfo> argList = new List<ArgInfo>();
      argList.Add(new ArgInfo(TypeEnu.Int, x));
      argList.Add(new ArgInfo(TypeEnu.Int, y));

      byte[] send_data = create_send_package("IMyService", "add", 2, TypeEnu.Int, argList);
      Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
      client.Connect(new IPEndPoint(IPAddress.Parse("192.168.0.105"), 10000));
      client.Send(send_data);

      byte[] buffer = new byte[4];
      int count = client.Receive(buffer);
      if (count > 0)
      {
        return bytes2int(buffer);
      }

      throw new Exception("系統(tǒng)異常");
    }

    public bool login(string name, string pwd)
    {
      List<ArgInfo> argList = new List<ArgInfo>();
      argList.Add(new ArgInfo(TypeEnu.String, name));
      argList.Add(new ArgInfo(TypeEnu.String, pwd));

      byte[] send_data = create_send_package("IMyService", "login", 2, TypeEnu.Bool, argList);
      Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
      client.Connect(new IPEndPoint(IPAddress.Parse("192.168.0.105"), 10000));
      client.Send(send_data);

      byte[] buffer = new byte[1];
      int count = client.Receive(buffer);
      if (count > 0)
      {
        return buffer[0] == 1;
      }

      throw new Exception("系統(tǒng)異常");
    }

    private byte[] create_send_package(string inter_name, string method_name, int arg_length, TypeEnu return_type, List<ArgInfo> argList)
    {
      List<byte> list = new List<byte>();
      list.Add((byte)inter_name.Length);
      list.AddRange(Encoding.UTF8.GetBytes(inter_name));

      list.Add((byte)method_name.Length);
      list.AddRange(Encoding.UTF8.GetBytes(method_name));

      list.Add((byte)arg_length);
      list.Add((byte)return_type);

      foreach (var arg in argList)
      {
        list.Add((byte)arg.type);
        if (arg.type == TypeEnu.Int)
        {
          list.AddRange(int2bytes(Convert.ToInt32(arg.value)));
        }
        else if (arg.type == TypeEnu.Bool)
        {
          bool value = Convert.ToBoolean(arg.value);
          list.Add(value ? (byte)1 : (byte)0);
        }
        else if (arg.type == TypeEnu.String)
        {
          string value = arg.value.ToString();
          list.AddRange(int2bytes(value.Length));
          list.AddRange(Encoding.UTF8.GetBytes(value));
        }
      }

      return list.ToArray();
    }

    public byte[] int2bytes(int len)
    {
      byte[] data_len = new byte[4];
      data_len[0] = (byte)((len >> 8 * 3) & 0xFF);
      data_len[1] = (byte)((len >> 8 * 2) & 0xFF);
      data_len[2] = (byte)((len >> 8 * 1) & 0xFF);
      data_len[3] = (byte)(len & 0xFF);

      return data_len;
    }

    public int bytes2int(byte[] buffer)
    {
      int value = 0;
      value += (int)(buffer[0] << (8 * 3));
      value += (int)(buffer[1] << (8 * 2));
      value += (int)(buffer[2] << (8 * 1));
      value += (int)(buffer[3]);

      return value;
    }
  }

  public class ArgInfo
  {
    public TypeEnu type { get; set; }

    public object value { get; set; }

    public ArgInfo(TypeEnu type, object value)
    {
      this.type = type;
      this.value = value;
    }
  }

  public enum TypeEnu
  {
    Void = 0,
    Int = 1,
    Bool = 2,
    String = 3
  }

  接口的定義沿用服務(wù)端的即可。說明一點:MyServiceProxy這個類,這里我是手寫的,真實的環(huán)境,這個類,應(yīng)該是由我們定義的某種格式,然后寫一個代碼生成器,讓他自動生成,然后就可以不用費(fèi)力,兼容所有的調(diào)用了,

當(dāng)然這里只支持了四種類型,我們還可以擴(kuò)充更多類型,只需要找到傳遞數(shù)據(jù)的方式即可。譬如一種對象,我們不知道如何傳遞,可以直接把對象定義成一個json字符串,或者序列化成二進(jìn)制,只要兩端,都知道了這個類型,就可以了。

相當(dāng)于設(shè)計模式里面的(約定大于配置了)

  知識點梳理

  這里有一些知識點,是不常用的,這里梳理出來了。

  1、MemoryStream ms = new MemoryStream(buffer); BinaryReader br = new BinaryReader(ms); 通過binaryReader的方式,可以像C/C++指針一樣取數(shù)據(jù)

  2、var types = Assembly.GetExecutingAssembly().GetTypes(); 通過Assembly可以得到當(dāng)前exe或者dll的所有類型(類接口都是一種類型)

  3、Object thisObj = Activator.CreateInstance(inter_type); 通過Activator調(diào)用默認(rèn)構(gòu)造,實現(xiàn)對象的初始化

  總結(jié):

  這樣一個rpc框架,本身并沒有優(yōu)化,還有很多地方是可以優(yōu)化的,比如:緩存(不用每次遍歷查詢類型等),udp支持(這里僅僅只是對tcp進(jìn)行了支持),

自動代碼生成(定義一種規(guī)范和支持程序,進(jìn)行支持),錯誤重試,數(shù)據(jù)唯一性,數(shù)據(jù)包的大小處理,等等,所以想要開發(fā)一個易用的框架,還需要不斷演進(jìn),這里只是對他的原理進(jìn)行了簡單剖析。

  最后還原大家拍磚。。。。。動起來

  代碼:git:https://github.com/supperlitt/tcp_all

以上就是c# RPC框架的使用簡介的詳細(xì)內(nèi)容,更多關(guān)于c# RPC框架的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • c#開發(fā)word批量轉(zhuǎn)pdf源碼分享

    c#開發(fā)word批量轉(zhuǎn)pdf源碼分享

    已經(jīng)安裝有Office環(huán)境,借助一些簡單的代碼即可實現(xiàn)批量Word轉(zhuǎn)PDF,看下面的實例源碼吧
    2013-12-12
  • 詳解C#操作XML的方法總結(jié)

    詳解C#操作XML的方法總結(jié)

    這篇文章主要為大家詳細(xì)介紹了C#對XML文件進(jìn)行一些基本操作的方法,譬如:生成xml文件、修改xml文件的節(jié)點信息等,需要的可以參考一下
    2022-11-11
  • C#多線程中的異常處理操作示例

    C#多線程中的異常處理操作示例

    這篇文章主要介紹了C#多線程中的異常處理操作,涉及C#多線程及異常的捕獲、處理等相關(guān)操作技巧,需要的朋友可以參考下
    2019-05-05
  • c# 引用類型與值類型的區(qū)別詳解

    c# 引用類型與值類型的區(qū)別詳解

    本篇文章是對c#中引用類型與值類型的區(qū)別進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • C# 實現(xiàn)顏色漸變窗體控件詳細(xì)講解

    C# 實現(xiàn)顏色漸變窗體控件詳細(xì)講解

    這篇文章主要介紹了C# 實現(xiàn)顏色漸變窗體控件詳細(xì)講解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • winform攔截關(guān)閉按鈕觸發(fā)的事件示例

    winform攔截關(guān)閉按鈕觸發(fā)的事件示例

    這篇文章主要介紹了c# winform攔截關(guān)閉按鈕觸發(fā)的事件示例,大家參考使用吧
    2014-01-01
  • C#中Linq的入門教程

    C#中Linq的入門教程

    這篇文章介紹了C#中Linq的基礎(chǔ)操作,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-05-05
  • 淺析wpf中datagrid顯示列的問題

    淺析wpf中datagrid顯示列的問題

    這篇文章主要為大家詳細(xì)介紹了wpf中datagrid顯示列問題的相關(guān)知識,文中的示例代碼講解詳細(xì),具有一定的借鑒價值,有需要的小伙伴可以學(xué)習(xí)一下
    2024-04-04
  • 分享用于操作FTP的客戶端C#類

    分享用于操作FTP的客戶端C#類

    用.net自帶的FtpWebRequest做的ftp客戶端得程序,有一個功能實現(xiàn)起來會非??嚯y,就是移動文件和文件夾的功能。所以后來又找了一個類,用socket實現(xiàn)的,發(fā)現(xiàn)比用ftpWebRequest功能要強(qiáng)。基本的ftp客戶端得命令都實現(xiàn)了。
    2015-05-05
  • C#使用第三方組件生成二維碼匯總

    C#使用第三方組件生成二維碼匯總

    本文給大家匯總了幾種C#使用第三方組件生成二維碼的方法以及示例,非常的簡單實用,都是項目中經(jīng)常需要用到的,希望大家能夠喜歡
    2016-12-12

最新評論