一、序言
本节须知
在学习本节之前,您必须熟悉RRQM中的Protocol服务器与客户端(或其派生类,例如文件传输和RPC)的创建,如果您不熟悉,请在下列链接中了解。
二、程序集源码、Demo下载
2.1 源码位置
RRQMSocket
2.2 Demo位置
RRQMBox
三、安装
安装RRQMSocket.RPC 即可,具体步骤详看链接博客。
VS、Unity安装和使用Nuget包
四、创建RPC
在之前【RRQMSocket.RPC】C# 创建多协议、多方式、多语言、多平台RPC框架中,已经提到创建服务方法,但是由于没有解析器 ,所以无法对服务进行下一步设置,那么这节就让我们来详细创建服务吧。
4.1 创建服务
在服务器项目 中新建一个类,继承于ServerProvider 类(或实现IServerProvider ),然后在该类中写公共方法,并用RRQMRPC 属性标签标记,如果方法有重载 ,需要重新指定函数键 ,方法可定义同步执行 ,也可以定义异步执行 。
public class MyRpcServer : ServerProvider
{
[RRQMRPC]
public string TestOne(int id)
{
return $"若汝棋茗,id={id}";
}
[RRQMRPC("TestOne_Name")]
public string TestOne(int id, string name)
{
return $"若汝棋茗,Name={name},id={id}";
}
[RRQMRPC]
public Task<string> AsyncTestOne(int id)
{
return Task.Run(() =>
{
return $"若汝棋茗,id={id}";
});
}
}
然后,创建TcpRpcParser解析器。在解析器中,设置类似TcpService 。
private static IRPCParser CreateRRQMTcpParser(int port)
{
TcpRpcParser tcpRPCParser = new TcpRpcParser();
var config = new TcpRpcParserConfig();
config.ListenIPHosts = new IPHost[] {new IPHost(port) };
config.BufferLength = 1024 * 64;
config.BytePoolMaxSize = 512 * 1024 * 1024;
config.BytePoolMaxBlockSize = 20 * 1024 * 1024;
config.Logger = new Log();
config.ServerName = "RRQMService";
config.SeparateThreadReceive = false;
config.ThreadCount = 5;
config.Backlog = 30;
config.ClearInterval = 60 * 1000;
config.ClearType = ClearType.Receive | ClearType.Send;
config.MaxCount = 10000;
config.VerifyToken = "123RPC";
config.VerifyTimeout = 3 * 1000;
config.CanResetID = true;
config.NameSpace = "RRQMTest";
config.RPCVersion = new Version(1, 0, 0, 0);
config.ProxyToken = "RPC";
tcpRPCParser.Setup(config);
tcpRPCParser.Start();
Console.WriteLine($"TCP解析器添加完成,端口号:{port},VerifyToken={tcpRPCParser.VerifyToken},ProxyToken={tcpRPCParser.ProxyToken}");
return tcpRPCParser;
}
最后添加解析器(添加时需要以键、值方式添加,方便后续查找),然后注册服务 即可。
服务器创建完成。
static void Main(string[] args)
{
RPCService rpcService = new RPCService();
rpcService.AddRPCParser("tcpRpcParser", CreateRRQMTcpParser(7794));
rpcService.RegisterServer<MyRpcServer>();
Console.WriteLine("RPC服务已启动");
}
五、发现、调用RPC服务
实例化TcpRpcClient,然后依托于内部方法,完成服务的发现与调用。
static void Main(string[] args)
{
TcpRpcClient client = new TcpRpcClient();
var config = new TcpRpcClientConfig();
config.RemoteIPHost = new IPHost("127.0.0.1:7794");
config.VerifyToken = "123RPC";
config.ProxyToken = "RPC";
client.Setup(config);
try
{
client.Connect();
Console.WriteLine("连接成功");
MethodItem[] methodItems = client.DiscoveryService();
Console.WriteLine("服务发现成功");
foreach (var item in methodItems)
{
Console.WriteLine($"服务{item.ServerName}中的‘{item.Method}’可以调用");
}
Console.WriteLine("按任意键调用TestOne");
Console.ReadKey();
string returnString = client.Invoke<string>("TestOne", InvokeOption.WaitInvoke, 10);
Console.WriteLine($"调用成功,结果={returnString}");
Console.ReadKey();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
六、调用痛点
RPC的创建与调用其实是一个比较简单的过程,但是要想更加智能化、便捷化的使用,还有很长的一段路要走。
在上述示例中不难发现,RPC的调用实际上是一个非常麻烦且难以维护的过程。麻烦的是调用者必须准确的知晓服务方法名称 ,且要传入类型结构相同的数据类型,尤其是后者,麻烦点甚多。而维护,也是疲不胜烦,每当服务端增加、修改、删除某个服务时,客户端也必须同步修改,这给产品更新,增加了不小的难度。
所以,我们想要的RPC绝不能仅仅是这样的…破玩意。
七 、获取代理
使用RPC的原则就是像使用本地方法一样,让开发者感觉不到任何的不同。所以就必须把服务代理到本地,常见的方式有三种,动态代理,静态织入,静态编译。三种方式殊途同归,最终都是构建本地数据结构,然后和远程通信。三种方式各有优缺,具体如下:
优缺点 | 动态代理 | 静态织入 | 静态编译 |
---|
优点 | 动态构建类,灵活、适应性强。 | 静态代码生成,自定义类参数自动生成,修改较灵活,调用效率高 | 自定义类参数自动生成,密封性强,安全性高,调用效率高。 | 缺点 | 调用效率较低,自定义类参数须自行构建,实现须IL支持,对调用平台有要求,例如:IOS不允许动态类生成,则不可使用。 | 项目代码管理难统一,强迫症猝死 | 服务一旦有破坏性升级,则必须重新替换dll,灵活性几乎为0。 |
说明:
在RRQM中支持静态织入,静态编译两种方式,同时也预留了动态代理接口,但是由于作者精力有限,对IL较陌生,所以暂未实现动态代理,所以有IL强者有兴趣的话,请联系作者QQ:505554090,我们共同学习。
7.1 从服务器直接获取代理代码
实际上在TcpRpcParser完成服务注册以后,获取其Codes 属性,即可获得代理代码。
此时,你可以复制、或者直接把代理代码写成源代码 (cs文件)。
然后你可以把这个代码引入到客户端。
CellCode[] cellCodes = tcpRpcParser.Codes;
foreach (var item in cellCodes)
{
Console.WriteLine(item.Code);
File.WriteAllText(item.Name+".cs",item.Code);
}
7.2 编译代理代码
有时候,为防止篡改生成的代码,不想把代理代码直接投入使用,那可以考虑将代码单独编译成dll,在Net45及以上平台,支持直接编译。
然后将编译代码加载到客户端。
tcpRpcParser.CompilerProxy();
7.3 远程通过静态织入获取代理载体
需要依靠插件(或程序),直接获取服务,然后将代理源文件植入项目中。具体步骤如下:
a).下载、安装RRQMRPCVSIX插件
【下载】 访问以下任意连接下载插件,然后安装“RRQMRPCVSIX.vsix”即可。
b).下载、运行RRQMRPCTool工具
如果完成了a步骤,则可以忽略本步骤。如果VS版本太低,或不想安装VS插件,那下载 RRQMRPCTool运行工具即可。
解压后直接运行exe程序,界面和c步骤一致。
c).获取代理
【插件使用】 1.安装(下载)完成后,右击项目,即可见“重新引用RPC”菜单条目。 2.点击,填入参数,确定即可。 3.完成后,项目中会多出“RRQMRPC”文件夹,里面的文件既是代理文件。
【RRQMRPCTool使用】 1.运行exe后,需要先选择“目标项目”,选择到客户端项目的.csproj 文件。 2.然后,填入参数,确定即可。 3.完成后,项目中会多出“RRQMRPC”文件夹,里面的文件既是代理文件。
八、使用
在引入代理代码(dll或者.cs源码)后,即可以使用代理的类(MyRpcServer )。
使用代理的优点如下:
- 维护简单,客户端只需要重新运行工具即可获得新代理。
- 数据结构生成,假如RPC方法的参数是复杂类型,则会直接生成相同结构的数据。
- 方法说明,客户独很好的得知该方法的注释。
基础操作如下:
static void Main(string[] args)
{
TcpRpcClient client = new TcpRpcClient();
var config = new TcpRpcClientConfig();
config.RemoteIPHost = new IPHost("127.0.0.1:7794");
config.VerifyToken = "123RPC";
config.ProxyToken = "RPC";
client.Setup(config);
try
{
client.Connect();
Console.WriteLine("连接成功");
MethodItem[] methodItems = client.DiscoveryService();
Console.WriteLine("服务发现成功");
foreach (var item in methodItems)
{
Console.WriteLine($"服务{item.ServerName}中的‘{item.Method}’可以调用");
}
Console.WriteLine("按任意键调用TestOne");
Console.ReadKey();
MyRpcServer myRpcServer = new MyRpcServer(client);
string returnString = myRpcServer.TestOne(10);
Console.WriteLine($"调用成功,结果={returnString}");
Console.ReadKey();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
|