gRPC使用体验

起因

因为鱼做DCIM系统需要机器人在群内输出日志调试的需求,我就把原来给某群写的机器人Shrink改了改。

而且鱼还点名了我提供的API通过gRPC调用,所以我就去哔哩哔哩搜了一下gRPC的概念,顺带找了一下可用的nuget包。

使用

首先我在原Shrink的解决方案nuget中导入了Grpc.Tools Grpc.core Grpc.Net.Client Google.Protobuf后来得知有一些更新的包可以用,我现在使用的已经没有正常维护了。

然后是定义proto文件,定义好命名空间以及Service,我放了loglevel、msgtype、data等字段,定义了一个SendData方法供远程发送需要打印的日志。

同时在解决方案中添加以下内容,确保Build时能够生成相应的文件。
<Protobuf Include="proto\apiService.proto" GrpcServices="Server" />

之后就可以在我的Shrink这里实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
using Debugger;
using Grpc.Core;
using Shrink.Logger;

namespace Shrink.Service;

public class ApiService : APIService.APIServiceBase
{
private static readonly Lazy<ApiService> _instance = new(() => new ApiService());
public static ApiService Instance => _instance.Value;


public override Task<DataResponse> SendData(DataRequest request, ServerCallContext context)
{
LogManager.Instance.LogChain.LogMessage(request.Data, request.Event, request.LogLevel, request.MsgType,
request.Uin, request.Text);
var response = new DataResponse();
if (LogManager.Instance.IsSent)
{
response.Message = $"已发送至: {request.Uin}。";
response.Success = true;
}
else
{
response.Message = "未发送,可能的原因是信息被设置为忽略或出现其他问题。";
response.Success = false;
}

LogManager.Instance.IsSent = false;
return Task.FromResult(response);
}
}

远端也足够简单,复制一下proto,设置好解决方案

<Protobuf Include="API/service.proto" GrpcServices="Client" />

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
using Debugger;
using Grpc.Net.Client;

namespace GrpcClient
{
internal static class Program
{
private static async Task Main()
{
// 初始化 gRPC 客户端
using var channel = GrpcChannel.ForAddress("https://localhost:5001");
var client = new APIService.APIServiceClient(channel);


// 准备请求数据
var request = new DataRequest
{
LogLevel = LogLevel.Info,
MsgType = MsgType.Public,
Uin = 954600523,
Data = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
Event = "TestEvent",
Text = "逸一时误一世"
};


// 调用 gRPC 服务
Console.WriteLine("向服务端发送请求...");
var response = await client.SendDataAsync(request);

// 输出响应结果
Console.WriteLine($"收到服务端响应:{response.Message}, Success: {response.Success}");
}
}
}

然后Shrink启动等待远程的请求即可。

总结

gRPC使用起来十分简单,通过一个proto文件即可实现数据的序列化和反序列化处理,而且还能够跨语言使用。
如果应用在Unity,那也能手搓一个网络框架出来。