<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      C#之rpc很火么?

      寫在前面:

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

      解釋:

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

      使用初探:

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

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

        2、然后服務端集成,

        3、客戶端集成,

        4、OK調用生效了。

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

           下面動手寫一個吧。

      自己動手:

        服務端:

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

          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,服務端的大部分完成了。

        然后就是TCP服務器,TCP服務器對大家來說,就太簡單不過了,不就是創建一個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服務器已啟動");
                  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);
              }
          }

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

        這里創建,一個ServiceHelpers來幫助對,真實算法的調用。如下:

          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; } }

        解析的類很簡單,因為這里創建的數據結構很簡單。

       

       

        按照我們的約定,這里,對數據按照我定義的方式來進行解包即可。

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

        客戶端:

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

      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();
              }
          }

        上面直接調用了,接口,至于接口的實現,這里的步驟就三個:1、構造需要請求的數據,2、連接服務器并發送數據,3、接收返回內容,并解析結果。

          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("系統異常");
              }
      
              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("系統異常");
              }
      
              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
          }

        接口的定義沿用服務端的即可。說明一點:MyServiceProxy這個類,這里我是手寫的,真實的環境,這個類,應該是由我們定義的某種格式,然后寫一個代碼生成器,讓他自動生成,然后就可以不用費力,兼容所有的調用了,

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

      相當于設計模式里面的(約定大于配置了)

        知識點梳理

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

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

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

        3、Object thisObj = Activator.CreateInstance(inter_type); 通過Activator調用默認構造,實現對象的初始化

        總結:

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

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

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

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

      posted @ 2021-02-04 09:12  Supper_litt  閱讀(626)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 国产精品无码免费播放| 亚洲免费的福利片| 国产欧美性成人精品午夜| 在线观看国产成人av片| 亚洲av午夜成人片| 日韩一区精品视频一区二区| 精品国产乱码久久久久久影片| 亚洲人妻一区二区精品| 巴楚县| 国产精品久久露脸蜜臀| 国产精品午夜精品福利| 无码日韩做暖暖大全免费不卡| 99国产精品永久免费视频| A级毛片无码久久精品免费| 四虎影视www在线播放| 国产超高清麻豆精品传媒麻豆精品| 精品视频在线观看免费观看| 国产无遮挡猛进猛出免费| 国产中文三级全黄| 日韩永久永久永久黄色大片| 99九九视频高清在线| 不卡乱辈伦在线看中文字幕| 亚洲人妻中文字幕一区| 五河县| 蜜臀av一区二区三区日韩| 久久久精品人妻一区二区三区蜜桃| 永久免费在线观看蜜桃视频| 日韩精品一区二区三区视频| 日韩精品18禁一区二区| 高清破外女出血AV毛片| 国产中文字幕精品喷潮| 国产一区二区不卡在线视频| 又爽又黄又无遮挡的视频| 蜜桃av亚洲精品一区二区| 欧美一区二区三区成人久久片| 久久精品国产精品亚洲精品| 露脸国产精品自产拍在线观看| 亚洲熟妇丰满多毛xxxx| 中文字幕一区二区网站| 夜爽8888视频在线观看| 国产明星精品无码AV换脸|