基于动态代理的WebAPI/RPC/webSocket框架,一套接口定义,多个通讯方式
API/RPC/webSocket三个看起来好像没啥相同的地方,在开发时,服务端,客户端实现代码也大不一样
最近整理了一下,通过动态代理的形式,整合了这些开发,都通过统一的接口约束,服务端实现和客户端调用
基于这样的形式,WebAPI/RPC/webSocket只需要定义一套接口,就能达到通用的效果
示例接口约束
public class TestObj
{
public string Name { get; set; }
}
public interface ITestService
{
void Login();
bool Test1(int a,int? b,out string error);
TestObj Test2(TestObj obj);
}
public class TestService : AbsService, ITestService
{
[LoginPoint]
public void Login()
{
SaveSession("hubro", "", "test");
} public bool Test1(int a, int? b, out string error)
{
var user = CurrentUserName;
var tag = CurrentUserTag; error = "out error";
Console.WriteLine(a);
Console.WriteLine(b);
return true;
} public TestObj Test2(TestObj obj)
{
Console.WriteLine(obj.ToJson());
return obj;
}
}
上面是一个标准接口和接口实现,并继承了AbsService,
Login方法标注了LoginPoint特性,表示登录切入点,调用此接口时首先得调用此方法,方法内SaveSession存储登录状态
Test1方法内使用了CurrentUserName,以获取登录方法保存的Session
特点:
- 通过接口约束服务端和客户端调用,参数定义透明化,out也支持
- 真正的方法远程调用,任意参数类型,个数
- 集成登录认证逻辑,自定义登录认证过程,也可以自定义Session实现
- 集成简单数据签名,不用费心数据安全问题
技术实现:
- Dynamitey实现接口类型代理
- DotNetty实现TCP通讯
- 对象二进制序列化
RPC调用
服务端
var server = new ServerCreater().CreatetRPC();
server.CheckSign();
server.SetSessionManage(new SessionManage());
server.Register<ITestService, TestService>();
server.Start();
CreateRPC是一个扩展方法,引用CRL.RPC获取
SetSessionManage,自定义Session存储,默认是内存里
CheckSign 处理请求时,进行参数签名验证
客户端接口调用
var clientConnect = new RPCClientConnect("127.0.0.1", 805);
clientConnect.UseSign();
var service = clientConnect.GetClient<ITestService>();
label1:
service.Login();
Console.WriteLine("loginOk");
int? a = 1;
string error;
service.Test1(1, a, out error);
Console.WriteLine("error:" + error);
var obj2 = service.Test2(new TestObj() { Name = "test" });
Console.WriteLine("obj2:" + obj2.ToJson());
Console.ReadLine();
goto label1;
客户端先调用login方法进行登录,并记录服务端返回的token
Test1方法将token回传给服务器以验证登录状态,并进行远程调用
当调用了UseSign方法,就会对提交的参数进行签名,签名KEY为登录后服务端返回的TOKEN,服务端同样按此对签名进行比较
动态webApi
同样基于上文结构,接口定义就不粘贴了
服务端定义
var server = new ServerCreater().CreatetApi();
server.CheckSign();
server.SetSessionManage(new SessionManage());
server.Register<ITestService, TestService>();
var listener = new ServerListener();
//listener.Start("http://localhost:809/");//自定义监听
如果宿主是.NET网站 在web.config增加处理module
<system.webServer>
<modules>
<add name="DynamicModule" type="CRL.DynamicWebApi.DynamicModule" />
</modules>
</system.webServer>
如果是单独程序,启动ServerListener即可
客户端调用
var clientConnect = new CRL.DynamicWebApi.ApiClientConnect("http://localhost:53065");
//var clientConnect = new CRL.DynamicWebApi.ApiClientConnect("http://localhost:8022");
clientConnect.UseSign();
var service = clientConnect.GetClient<ITestService>();
label1:
service.Login();
Console.WriteLine("loginOk");
int? a = ;
string error;
service.Test1(, a, out error);
Console.WriteLine("error:" + error);
var obj2 = service.Test2(new TestObj() { Name = "test" });
Console.WriteLine("obj2:" + obj2.ToJson());
Console.ReadLine();
goto label1;
WebSocket
WebSocket是一个比较特殊的方式,常用来做双工通讯的方式,客户端能往服务端发送数,服务端也能往客户端发送据
除去服务端往客户端发数据,也可以采用接口调用的形式实现,在这里,服务端往客户端发送数据,客户端采用了订阅的方式
服务端实现
var server = new ServerCreater().CreatetWebSocket(8015);
server.CheckSign();
server.SetSessionManage(new SessionManage());
server.Register<ITestService, TestService>();
server.Start();
new CRL.Core.ThreadWork().Start("send", () =>
{
var socket = server.GetServer() as CRL.WebSocket.WebSocketServer;
socket.SendMessage("hubro", new socketMsg() { name = DateTime.Now.ToString() }, out string error);
Console.WriteLine("send msg");
return true;
}, 10);
上面演示代码,服务端开启了一个线程,定时往客户端"hubro"发送数据 socket.SendMessage
客户端实现
var clientConnect = new CRL.WebSocket.WebSocketClientConnect("127.0.0.1", );
clientConnect.UseSign();
clientConnect.SubscribeMessage<socketMsg>((obj) =>
{
Console.WriteLine("OnMessage:" + obj.ToJson());
});
clientConnect.StartPing();
var service = clientConnect.GetClient<ITestService>();
label1:
service.Login();
Console.WriteLine("loginOk");
int? a = ;
string error;
service.Test1(, a, out error);
Console.WriteLine("error:" + error);
var obj2 = service.Test2(new TestObj() { Name = "test" });
Console.WriteLine("obj2:" + obj2.ToJson());
Console.ReadLine();
goto label1;
clientConnect.SubscribeMessage就是订阅消息了,通过订阅的方式,处理服务端发送的数据
可以看到以上各种形式,服务端实现和客户端调用基本相同,定义的接口能重复使用,做接口通讯效果杠杠的
具体实现方式和细节功能参见源码和demo,已经开源,请自行下载
源码地址:
CRL:
https://github.com/hubro-xx/CRL5
RCP:
https://github.com/hubro-xx/CRL5/tree/master/RPC
WebAPI:
https://github.com/hubro-xx/CRL5/tree/master/DynamicWebApi
WebSocket:
https://github.com/hubro-xx/CRL5/tree/master/WebSocket
基于动态代理的WebAPI/RPC/webSocket框架,一套接口定义,多个通讯方式的更多相关文章
- .NET 下基于动态代理的 AOP 框架实现揭秘
.NET 下基于动态代理的 AOP 框架实现揭秘 Intro 之前基于 Roslyn 实现了一个简单的条件解析引擎,想了解的可以看这篇文章 https://www.cnblogs.com/weihan ...
- 实现一个简单的基于动态代理的 AOP
实现一个简单的基于动态代理的 AOP Intro 上次看基于动态代理的 AOP 框架实现,立了一个 Flag, 自己写一个简单的 AOP 实现示例,今天过来填坑了 目前的实现是基于 Emit 来做的, ...
- 动态代理到基于动态代理的AOP
动态代理,是java支持的一种程序设计方法. 动态代理实现中有两个重要的接口和类,分别是InvocationHandler(interface),Proxy(class). 要实现动态代理,必须要定义 ...
- mybatis源码学习:基于动态代理实现查询全过程
前文传送门: mybatis源码学习:从SqlSessionFactory到代理对象的生成 mybatis源码学习:一级缓存和二级缓存分析 下面这条语句,将会调用代理对象的方法,并执行查询过程,我们一 ...
- MyBatis学习(三)MyBatis基于动态代理方式的增删改查
1.前言 上一期讲到MyBatis-Statement版本的增删改查.可以发现.这种代码写下来冗余的地方特别多.写一套没啥.如果涉及到多表多查询的时候就容易出现问题.故.官方推荐了一种方法.即MyBa ...
- Java通过Socket和动态代理实现简易RPC框架
本文转自Dubbo作者梁飞大神的CSDN(https://javatar.iteye.com/blog/1123915),代码简洁,五脏俱全. 1.首先实现RpcFramework,实现服务的暴露与引 ...
- JDK动态代理在RPC框架中的应用
RPC框架中一般都有3个角色:服务提供者.服务消费者和注册中心.服务提供者将服务注册到注册中心,服务消费者从注册中心拉取服务的地址,并根据服务地址向服务提供者发起RPC调用.动态代理在这个RPC调用的 ...
- 带你手写基于 Spring 的可插拔式 RPC 框架(一)介绍
概述 首先这篇文章是要带大家来实现一个框架,听到框架大家可能会觉得非常高大上,其实这和我们平时写业务员代码没什么区别,但是框架是要给别人使用的,所以我们要换位思考,怎么才能让别人用着舒服,怎么样才能让 ...
- Java动态代理——框架中的应用场景和基本原理
前言 之前已经用了5篇文章完整解释了java动态代理的原理,本文将会为这个系列补上最后一块拼图,展示java动态代理的使用方式和应用场景 主要分为以下4个部分 1.为什么要使用java动态代理 2.如 ...
随机推荐
- lightoj 1382 - The Queue(树形dp)
题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1382 题解:简单的树形dp加上组合数学. #include <iostr ...
- codeforces 808 D. Array Division(二分)
题目链接:http://codeforces.com/contest/808/problem/D 题意:有一串长度为n的数组,要求选择一个数字交换它的位置使得这串数能够分成两串连续的和一样的数组. 这 ...
- 原来JS是这样的 - 对象属性
引子 在上一篇(原来JS是这样的 (2))刚发布的时候就阅读了那篇文章的人可能会注意到那篇曾用过"JavaScript 中万物皆对象"的说法,而在随后我发现错误后立即更新改掉了这个 ...
- 这一次,彻底弄懂 Promise 原理
作者声明 本人将迁移至个人公众号「前端Q」及「掘金」平台写文章.博客园的文章将不再及时更新发布.欢迎大家关注公众号「前端Q」及我的掘金主页:https://juejin.im/user/5874526 ...
- [DP]矩阵的最小路径和
题目 给定一个矩阵m, 从左上角开始每次只能向右或者向下走,最后到达右下角的位置,路径上所有的树子累加起来就是路径和,返回所有的路径中最小的路径和. 解法一 这是一道经典的动态规划题,状态转移方程为d ...
- git之坑2
今天遇到的问题,git拉代码拉不了了,开发同事将他的家目录下的.ssh目录权限给改成777 造成pull push代码报错. 截图如下: 原因是哪个哥们把根目录的权限全部改为了777 解决方法,将他的 ...
- java学习笔记之基础篇
java选择语句之switch //switch可以用于等值判断 switch (e) //int ,或则可以自动转化成int 的类型,(byte char short)枚举jdk 7中可以防止字 ...
- Go语言基础之指针
区别于C/C++中的指针,Go语言中的指针不能进行偏移和运算,是安全指针. 要搞明白Go语言中的指针需要先知道3个概念:指针地址.指针类型和指针取值. Go语言中的指针 Go语言中的函数传参都是值拷贝 ...
- 个人IP「Android大强哥」上线啦!
自从入职新公司之后就一直忙得不行,一边熟悉开发的流程,一边熟悉各种网站工具的使用,一边又在熟悉业务代码,好长时间都没有更文了. 不过新公司的 mentor(导师)还是很不错的,教给我很多东西,让我也能 ...
- Android数据列表展示之 RecylerView
一.概述 1.RecyclerView是什么? RecyclerView是一种新的视图组,目标是为任何基于适配器的视图提供相似的渲染方式.该控件用于在有限的窗口中展示大量数据集,它被作为ListVie ...