Rpc原理详解

博客上已经有人解释的很详细了,我就不在解释了。传送门

项目简介

项目是依赖于.net core2.0版本,内部都是依靠IOC来实现的,方便做自定义扩展。底层的通信是采用socket,sokcet的代码参考Enode的socket代码。类的序列化目前只支持自带的BinarySerializer和Json.net,也可以自定义,扩展也很方便。也支持zookeeper的服务协调。

框架传输及序列化逻辑

当客户端发起请求时,根据建立的客户端代理,获取当前的请求方法信息(名字、所属类型、参数值),通过自带的BinarySerializer将其序列化,所以在传输的方法中的自定义的类就必须加上【Serializable】可序列化标记,不然会报错。客户端将请求的方法信息序列化成字节数组之后传输到服务端,服务端获取到信息后根据方法信息获取到要执行的方法,然后执行该方法,并将结果返回给客户端。返回结果的序列化可以采用自定义的标记来进行,比如在方法或者类上面打上【BinarySerializer】标记,则采用BinarySerializer序列化,打上【JsonSerializer】标记则采用json.net来序列化话,后期可以支持protobuf来序列化。

服务端代码

首先定义一个接口和一个实现类

namespace NetCoreRpc.Application
{
public interface IStudentApplication
{
int Age(); bool IsYongPeople(int age); void Say(string msg); Task Sleep(); Task<int> RunAsync(int sleepTime); void Say(byte[] msg); byte[] Say(); [BinarySerializer]
TestModel Test();
} public class StudentApplication : IStudentApplication
{
public int Age()
{
return ;
} public bool IsYongPeople(int age)
{
return age < ;
} public async Task<int> RunAsync(int sleepTime)
{
await Task.Delay(sleepTime);
return sleepTime;
} public void Say(string msg)
{
Console.WriteLine($"Say:{msg}");
} public Task Sleep()
{
return Task.Delay();
} public void Say(byte[] msg)
{
Console.WriteLine(Encoding.UTF8.GetString(msg));
} public byte[] Say()
{
return Encoding.UTF8.GetBytes("Good Job!");
} public TestModel Test()
{
return new TestModel
{
Age = ,
Msg = Encoding.UTF8.GetBytes("Hello")
};
}
} [Serializable]
public class TestModel
{
public int Age { get; set; } public byte[] Msg { get; set; } public override string ToString()
{
return $"{Age}|{Encoding.UTF8.GetString(Msg)}";
}
}
}

IStudentApplication

不基于zookeeper的服务端版本

    internal class Program
{
public static IConfigurationRoot Configuration; private static void Main(string[] args)
{
Console.WriteLine("请输入监听端口:");
var strPort = Console.ReadLine();
var builder = new ConfigurationBuilder();
//.SetBasePath(Path.Combine(AppContext.BaseDirectory)).AddJsonFile("NetCoreRpc.json", optional: true);
Configuration = builder.Build();
var servicesProvider = BuildDi();
DependencyManage.SetServiceProvider(servicesProvider, Configuration);
NRpcServer nrpcServer = new NRpcServer(int.Parse(strPort));
nrpcServer.Start("NetCoreRpc.Application");
Console.WriteLine("Welcome to use NetCoreRpc!");
Console.WriteLine("Input exit to exit");
var str = Console.ReadLine();
while (!string.Equals(str, "exit", StringComparison.OrdinalIgnoreCase))
{
str = Console.ReadLine();
}
nrpcServer.ShutDown();
} private static IServiceProvider BuildDi()
{
IServiceCollection services = new ServiceCollection(); services.AddSingleton<ILoggerFactory, LoggerFactory>();
services.AddSingleton(typeof(ILogger<>), typeof(Logger<>));
services.AddSingleton<IStudentApplication, StudentApplication>();
services.UseRpc();
//.UseZK();
var serviceProvider = services.BuildServiceProvider(); var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>(); loggerFactory.AddNLog(new NLogProviderOptions { CaptureMessageTemplates = true, CaptureMessageProperties = true });
loggerFactory.ConfigureNLog("NLog.config"); return serviceProvider;
}
}

Server

基于zookeeper的服务端版本

    internal class Program
{
public static IConfigurationRoot Configuration; private static void Main(string[] args)
{
Console.WriteLine("请输入监听端口:");
var strPort = Console.ReadLine();
var builder = new ConfigurationBuilder()
.SetBasePath(Path.Combine(AppContext.BaseDirectory)).AddJsonFile("NetCoreRpc.json", optional: true);
Configuration = builder.Build();
var servicesProvider = BuildDi();
DependencyManage.SetServiceProvider(servicesProvider, Configuration);
NRpcServer nrpcServer = new NRpcServer(int.Parse(strPort));
nrpcServer.Start("NetCoreRpc.Application");
Console.WriteLine("Welcome to use NetCoreRpc!");
Console.WriteLine("Input exit to exit");
var str = Console.ReadLine();
while (!string.Equals(str, "exit", StringComparison.OrdinalIgnoreCase))
{
str = Console.ReadLine();
}
nrpcServer.ShutDown();
} private static IServiceProvider BuildDi()
{
IServiceCollection services = new ServiceCollection(); services.AddSingleton<ILoggerFactory, LoggerFactory>();
services.AddSingleton(typeof(ILogger<>), typeof(Logger<>));
services.AddSingleton<IStudentApplication, StudentApplication>();
services.UseRpc()
.UseZK();
var serviceProvider = services.BuildServiceProvider(); var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>(); loggerFactory.AddNLog(new NLogProviderOptions { CaptureMessageTemplates = true, CaptureMessageProperties = true });
loggerFactory.ConfigureNLog("NLog.config"); return serviceProvider;
}
}

基于zookeeper的版本

客户端代码

首先要引用刚刚定义的接口和Model

    internal class Program
{
public static IConfigurationRoot Configuration; private static void Main(string[] args)
{
var builder = new ConfigurationBuilder().SetBasePath(Path.Combine(AppContext.BaseDirectory)).AddJsonFile("NetCoreRpc.json", optional: true);
Configuration = builder.Build(); var servicesProvider = BuildDi();
DependencyManage.SetServiceProvider(servicesProvider, Configuration); Console.WriteLine("Welcome to use NetCoreRpc!");
var studentApplication = ProxyFactory.Create<IStudentApplication>();
Console.WriteLine(studentApplication.Age());
Console.WriteLine(studentApplication.IsYongPeople());
var runTask = studentApplication.RunAsync();
studentApplication.Say("Hello world");
studentApplication.Say(Encoding.UTF8.GetBytes("Hi!"));
Console.WriteLine(Encoding.UTF8.GetString(studentApplication.Say()));
var test = studentApplication.Test();
Console.WriteLine(test.ToString());
studentApplication.Sleep();
Console.WriteLine(runTask.Result); Console.WriteLine("Input exit to exit");
var str = Console.ReadLine();
while (!string.Equals(str, "exit", StringComparison.OrdinalIgnoreCase))
{
str = Console.ReadLine();
}
} private static IServiceProvider BuildDi()
{
IServiceCollection services = new ServiceCollection();
services.AddOptions();
services.Configure<RemoteEndPointConfig>(Configuration.GetSection("NetCoreRpc"));
services.AddSingleton<ILoggerFactory, LoggerFactory>();
services.AddSingleton(typeof(ILogger<>), typeof(Logger<>));
services.UseRpc().UseZK();
var serviceProvider = services.BuildServiceProvider(); var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>(); //configure NLog
loggerFactory.AddNLog(new NLogProviderOptions { CaptureMessageTemplates = true, CaptureMessageProperties = true });
loggerFactory.ConfigureNLog("NLog.config"); return serviceProvider;
}
}

客户端基于zookeeper

{
"NetCoreRpc": {
"Default": "192.168.129.194:12346,192.168.129.194:12347,192.168.129.194:12348",
"Group": [
{
"NameSpace": "",
"Address": "127.0.0.1:12345"
}
],
"Zookeeper": {
"Connection": "192.168.100.34:2181",
"ParentName": "/NetCoreRpc/ClientTest"
}
}
}

NetCoreRpc.json

    internal class Program
{
public static IConfigurationRoot Configuration; private static void Main(string[] args)
{
var builder = new ConfigurationBuilder().SetBasePath(Path.Combine(AppContext.BaseDirectory)).AddJsonFile("NetCoreRpc.json", optional: true);
Configuration = builder.Build(); var servicesProvider = BuildDi();
DependencyManage.SetServiceProvider(servicesProvider, Configuration); Console.WriteLine("Welcome to use NetCoreRpc!");
var studentApplication = ProxyFactory.Create<IStudentApplication>();
Console.WriteLine(studentApplication.Age());
Console.WriteLine(studentApplication.IsYongPeople());
var runTask = studentApplication.RunAsync();
studentApplication.Say("Hello world");
studentApplication.Say(Encoding.UTF8.GetBytes("Hi!"));
Console.WriteLine(Encoding.UTF8.GetString(studentApplication.Say()));
var test = studentApplication.Test();
Console.WriteLine(test.ToString());
studentApplication.Sleep();
Console.WriteLine(runTask.Result); Console.WriteLine("Input exit to exit");
var str = Console.ReadLine();
while (!string.Equals(str, "exit", StringComparison.OrdinalIgnoreCase))
{
str = Console.ReadLine();
}
} private static IServiceProvider BuildDi()
{
IServiceCollection services = new ServiceCollection();
services.AddOptions();
services.Configure<RemoteEndPointConfig>(Configuration.GetSection("NetCoreRpc"));
services.AddSingleton<ILoggerFactory, LoggerFactory>();
services.AddSingleton(typeof(ILogger<>), typeof(Logger<>));
services.UseRpc();//.UseZK();
var serviceProvider = services.BuildServiceProvider(); var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>(); //configure NLog
loggerFactory.AddNLog(new NLogProviderOptions { CaptureMessageTemplates = true, CaptureMessageProperties = true });
loggerFactory.ConfigureNLog("NLog.config"); return serviceProvider;
}
}

不基于zookeeper的代码

NetCoreRpc.json中的Zookeeper节点可以不用配置

调用测试结果

服务端输出如下:

客户端输出如下:

项目中感觉不足之处

1、传输时采用的序列化采用的是自带的BinarySerializer,需要在每个Model打上可序列化标记,后期希望改成不需要打标记就可以序列化的

2、采用zookeeper时,获取可用IP是获取当前第一个可用的IP,没有有任何的算法

3、其它目前还没有想到,如果各位博友有什么建议可以提一下,帮助我一下,谢谢

项目源码地址

GitHub

今天晚上在写这篇随笔的时候发现自己无从下手,博友有没有支招的啊,非常感谢。

基于.netcore 开发的轻量Rpc框架的更多相关文章

  1. Cardinal:一个用于移动项目开发的轻量 CSS 框架

    Cardinal 是一个适用于移动项目的 CSS 框架,包含很多有用的默认样式.矢量字体.可重用的模块以及一个简单的响应式模块系统.Cardinal 提供了一种在多种移动设备上实现可伸缩的字体和布局的 ...

  2. 基于Node和Electron开发了轻量版API接口请求调试工具——Post-Tool

    Electron 是一个使用 JavaScript.HTML 和 CSS 构建桌面应用程序的框架. 嵌入 Chromium 和 Node.js 到 二进制的 Electron 允许您保持一个 Java ...

  3. vue-calendar 基于 vue 2.0 开发的轻量,高性能日历组件

    vue-calendar-component 基于 vue 2.0 开发的轻量,高性能日历组件 占用内存小,性能好,样式好看,可扩展性强 原生 js 开发,没引入第三方库 Why Github 上很多 ...

  4. 基于HTTP/2和protobuf的RPC框架:GRPC

    谷歌发布的首款基于HTTP/2和protobuf的RPC框架:GRPC Google 刚刚开源了grpc,  一个基于HTTP2 和 Protobuf 的高性能.开源.通用的RPC框架.Protobu ...

  5. 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目

    系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 ... 基于. ...

  6. 基于.NetCore开发博客项目 StarBlog - (3) 模型设计

    系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...

  7. 基于.NetCore开发博客项目 StarBlog - (6) 页面开发之博客文章列表

    系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...

  8. 基于.NetCore开发博客项目 StarBlog - (9) 图片批量导入

    系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...

  9. 基于.NetCore开发博客项目 StarBlog - (11) 实现访问统计

    系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...

随机推荐

  1. C#中&与&&的区别

    c#&是什么意思? 看过一些文章,关于这个的简单而容易被忽略的语法,说的总有点瑕疵. 贴代码15秒之内应该能知道c#中一个&和两个&&的区别,开始计数了........ ...

  2. xamarin android制作圆角边框

    xamarin android制作圆角边框 效果图如下: 关键代码: drawable文件夹新建shape_corner_down.xml <?xml version="1.0&quo ...

  3. Structural Inference of Hierarchies in Networks(网络层次结构推断)

    Structural Inference of Hierarchies in Networks(网络层次结构推断) 1. 问题 层次结构是一种重要的复杂网络性质.这篇文章给出了层次结构的精确定义,给出 ...

  4. 读Zepto源码之assets模块

    assets 模块是为解决 Safari 移动版加载图片过大过多时崩溃的问题.因为没有处理过这样的场景,所以这部分的代码解释不会太多,为了说明这个问题,我翻译了<How to work arou ...

  5. bzoj 4013: [HNOI2015]实验比较

    Description 小D 被邀请到实验室,做一个跟图片质量评价相关的主观实验.实验用到的图片集一共有 N 张图片,编号为 1 到 N.实验分若干轮进行,在每轮实验中,小 D会被要求观看某两张随机选 ...

  6. 2、转载一篇,浅析人脸检测之Haar分类器方法

    转载地址http://www.cnblogs.com/ello/archive/2012/04/28/2475419.html 浅析人脸检测之Haar分类器方法  [补充] 这是我时隔差不多两年后, ...

  7. UWP 应用通知Notifications

    之前说UWP 使用OneDrive云存储2.x api(二)[全网首发],微识别实现了上传下载的功能,那么为了给用户更上一层楼的体验,那就是在上传下载完成之后,弹出一通知Notifications. ...

  8. 微信小程序一:微信小程序UI组件、开发框架、实用库

    作者:NiceCui 本文谢绝转载,如需转载需征得作者本人同意,谢谢. 本文链接:http://www.cnblogs.com/NiceCui/p/8079095.html 内容持续更新,维护中 邮箱 ...

  9. python实现散列表的链表法

    在散列中,链接法是一种最简单的碰撞解决技术,这种方法的原理就是把散列到同一槽中的所有元素 都放在一个链表中. 链接法有两个定理,定理一: 在简单一致散列的假设下,一次不成功查找的期望时间为O(1 + ...

  10. Web开发入门学习笔记

    公司web项目终于要启动了,本以为django学习可以在实战中进行,结果最终使用了Drupal框架,好吧,那我们就PHP走起,买了本<细说PHP>,先跟着过一遍Web开发入门. HTTP协 ...