基于.netcore 开发的轻量Rpc框架
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、其它目前还没有想到,如果各位博友有什么建议可以提一下,帮助我一下,谢谢
项目源码地址
今天晚上在写这篇随笔的时候发现自己无从下手,博友有没有支招的啊,非常感谢。
基于.netcore 开发的轻量Rpc框架的更多相关文章
- Cardinal:一个用于移动项目开发的轻量 CSS 框架
Cardinal 是一个适用于移动项目的 CSS 框架,包含很多有用的默认样式.矢量字体.可重用的模块以及一个简单的响应式模块系统.Cardinal 提供了一种在多种移动设备上实现可伸缩的字体和布局的 ...
- 基于Node和Electron开发了轻量版API接口请求调试工具——Post-Tool
Electron 是一个使用 JavaScript.HTML 和 CSS 构建桌面应用程序的框架. 嵌入 Chromium 和 Node.js 到 二进制的 Electron 允许您保持一个 Java ...
- vue-calendar 基于 vue 2.0 开发的轻量,高性能日历组件
vue-calendar-component 基于 vue 2.0 开发的轻量,高性能日历组件 占用内存小,性能好,样式好看,可扩展性强 原生 js 开发,没引入第三方库 Why Github 上很多 ...
- 基于HTTP/2和protobuf的RPC框架:GRPC
谷歌发布的首款基于HTTP/2和protobuf的RPC框架:GRPC Google 刚刚开源了grpc, 一个基于HTTP2 和 Protobuf 的高性能.开源.通用的RPC框架.Protobu ...
- 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 ... 基于. ...
- 基于.NetCore开发博客项目 StarBlog - (3) 模型设计
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
- 基于.NetCore开发博客项目 StarBlog - (6) 页面开发之博客文章列表
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
- 基于.NetCore开发博客项目 StarBlog - (9) 图片批量导入
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
- 基于.NetCore开发博客项目 StarBlog - (11) 实现访问统计
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
随机推荐
- 链表创建和链表遍历算法的演示_C语言
今天搞了一个多小时,头是疼的,应该是没休息好吧,学习了数据结构这一节,感觉收益良多,下面贴上代码和心得: /*24_链表创建和链表遍历算法的演示*/ # include <stdio.h> ...
- UVA 10559 Blocks
题目大意:有一串带颜色的方块,每次可以消掉颜色相同的一段,得到size^2的分数,问最多能得到多少分数.n≤200. 给这题状态跪下来. 显然的区间DP,但设f[i][j]是不够的. 考虑到之前做过的 ...
- Windows zip安装MySQL
1. mysqld初始化时my.ini的第二个默认位置是%windir%/my.ini rem 1.查看此变量对应的目录,在此目录下编辑 my.ini,mysqld会自动找到 echo %WINDIR ...
- ioutil包二
ioutil包二 (原创随笔,转载请注明出处 http://www.cnblogs.com/majianguo/p/8016426.html) ioutil包实现了一些I/O实用功能,导出了7个函数和 ...
- JavaScript的DOM编程--04--获取元素节点的子节点
获取元素节点的子节点(**只有元素节点才有子节点!!) 1). childNodes 属性获取全部的子节点, 但该方法不实用. 因为如果要获取指定的节点 的指定子节点的集合, 可以直接调用元素节点的 ...
- 前端之 HTML🎃
HTML这知识点很多很杂,所以整理很乱.所以将就看.
- 前端之 CSS🤖
css (层叠样式表) : 对html标签的渲染和布局 查找 (选择器) 操作标签 (属性操作) 导入用 link 标签,后面的href就用你的文件路径就好 写css文件,要单独写到一个文件里面去 推 ...
- 一个IC软件工程师的2017年终工作总结
相比2016年的波澜起伏,2017多了一份平静和清淡.不过,平静的生活下,总有一颗飞向远方的心. 在这一年将近结束的时候,总结一下自己的工作,生活和学习.也顺便展望一下未来的2018,看看有哪些 美好 ...
- Fiddler如何模拟弱网环境进行测试
1.模拟弱网环境 打开Fiddler,Rules->Performance->勾选 Simulate Modem Speeds,勾选之后访问网站会发现网络慢了很多 2.Fiddler弱网的 ...
- HashMap分析之红黑树树化过程
概述 HashMap是Java程序员使用频率最高的用于映射(键值对)处理的数据类型.随着JDK(Java Developmet Kit)版本的更新,JDK1.8对HashMap底层的实现进行了优化,例 ...