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框架,一套接口定义,多个通讯方式的更多相关文章

  1. .NET 下基于动态代理的 AOP 框架实现揭秘

    .NET 下基于动态代理的 AOP 框架实现揭秘 Intro 之前基于 Roslyn 实现了一个简单的条件解析引擎,想了解的可以看这篇文章 https://www.cnblogs.com/weihan ...

  2. 实现一个简单的基于动态代理的 AOP

    实现一个简单的基于动态代理的 AOP Intro 上次看基于动态代理的 AOP 框架实现,立了一个 Flag, 自己写一个简单的 AOP 实现示例,今天过来填坑了 目前的实现是基于 Emit 来做的, ...

  3. 动态代理到基于动态代理的AOP

    动态代理,是java支持的一种程序设计方法. 动态代理实现中有两个重要的接口和类,分别是InvocationHandler(interface),Proxy(class). 要实现动态代理,必须要定义 ...

  4. mybatis源码学习:基于动态代理实现查询全过程

    前文传送门: mybatis源码学习:从SqlSessionFactory到代理对象的生成 mybatis源码学习:一级缓存和二级缓存分析 下面这条语句,将会调用代理对象的方法,并执行查询过程,我们一 ...

  5. MyBatis学习(三)MyBatis基于动态代理方式的增删改查

    1.前言 上一期讲到MyBatis-Statement版本的增删改查.可以发现.这种代码写下来冗余的地方特别多.写一套没啥.如果涉及到多表多查询的时候就容易出现问题.故.官方推荐了一种方法.即MyBa ...

  6. Java通过Socket和动态代理实现简易RPC框架

    本文转自Dubbo作者梁飞大神的CSDN(https://javatar.iteye.com/blog/1123915),代码简洁,五脏俱全. 1.首先实现RpcFramework,实现服务的暴露与引 ...

  7. JDK动态代理在RPC框架中的应用

    RPC框架中一般都有3个角色:服务提供者.服务消费者和注册中心.服务提供者将服务注册到注册中心,服务消费者从注册中心拉取服务的地址,并根据服务地址向服务提供者发起RPC调用.动态代理在这个RPC调用的 ...

  8. 带你手写基于 Spring 的可插拔式 RPC 框架(一)介绍

    概述 首先这篇文章是要带大家来实现一个框架,听到框架大家可能会觉得非常高大上,其实这和我们平时写业务员代码没什么区别,但是框架是要给别人使用的,所以我们要换位思考,怎么才能让别人用着舒服,怎么样才能让 ...

  9. Java动态代理——框架中的应用场景和基本原理

    前言 之前已经用了5篇文章完整解释了java动态代理的原理,本文将会为这个系列补上最后一块拼图,展示java动态代理的使用方式和应用场景 主要分为以下4个部分 1.为什么要使用java动态代理 2.如 ...

随机推荐

  1. HDU-10240Max Sum Plus Plus+动态规划+滚动数组

    Max Sum Plus Plus 题意:题意理解了老半天,这里是说在给定数列中,取m组子数列,不能有重复,使得这些子序列的和最大: 就比如m=2时候,1 /2/-4/5/6.可以不用拿-4的意思: ...

  2. light 1205 - Palindromic Numbers(数位dp)

    题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1205 题解:这题作为一个数位dp,是需要咚咚脑子想想的.这个数位dp方程可能不 ...

  3. 2019 HZNU Winter Training Day 14 Comprehensive Training

    A - Choosing Capital for Treeland CodeForces - 219D 题意:有一颗单向边的树,要选取一个结点作为首都.要求是这个结点到其它结点,总共需要翻转的路径数量 ...

  4. 模板类型推导、auto推导

    effective modern c++ 果然是神书,干货满满,简单记录下. item1 模板推倒 典型的模板函数 temlate<class T> void fn(ParamType p ...

  5. 变量的范围 namespace

    变量的范围 范围 变量有 菊部变量 和 全局变量之分, local variable 和 global variable 一般在函数体外定义的变量是全局的,函数体内定义的变量只能在函数内使用 注意:在 ...

  6. 适合C++のOIer平日写题的开场模板

    上面的#define还是较充足的,快读模板也有,freopen也提前打好了,比较适合OIer(C++)平时刷题和考试的开场. (纯原版仅供SJZEZのORZ队&AFO队使用) (您老把开头的注 ...

  7. 为什么不建议使用Date,而是使用Java8新的时间和日期API?

    Java 8:新的时间和日期API 在Java 8之前,所有关于时间和日期的API都存在各种使用方面的缺陷,因此建议使用新的时间和日期API,分别从旧的时间和日期的API的缺点以及解决方法.Java ...

  8. TensorFlow读取数据的三种方法

    tensortlfow数据读取有三种方式 placehold feed_dict:从内存中读取数据,占位符填充数据 queue队列:从硬盘读取数据 Dataset:同时支持内存和硬盘读取数据 plac ...

  9. 史上最全面的SignalR系列教程-目录汇总

    1.引言 最遗憾的不是把理想丢在路上,而是理想从未上路. 每一个将想法变成现实的人,都值得称赞和学习. 致正在奔跑的您! 2.SignalR介绍 SignalR实现服务器与客户端的实时通信 ,她是一个 ...

  10. 从原理到场景 系统讲解 PHP 缓存技术

    第1章课程介绍 此为PHP相关缓存技术的课堂,有哪些主流的缓存技术可以被使用? 第1章 课程介绍 1-1课程介绍1-2布置缓存的目的1-3合理使用缓存1-4哪些环节适合用缓存 第2章 文件类缓存 2- ...