1.理解GRPC
GRPC
本质上是通过谷歌开源的protobuff
标准协议实现的传输,和http
那种类似,但是他更高效,因为他底层数据是通过二进制传输,比传统的json
快很多,通常用于直播间的推流送流。
2.为什么用GRPC
最开始只想解决跨进程通信,用传统的MQ
就可以实现,但是GRPC
近些年也越来越火了,就试了试。因为他更标准,兼容性更好,可以跨语言跨脚本使用,大家按照他的标准去定义调用就好了。
3.C#应用和Python应用如何通过GRPC互相调用
在这里我C#应用做为GRPC的服务端。Python应用作为客户端去调用。
3.1首先定义标准.proto文件
csharp
syntax = "proto3";
option csharp_namespace = "DY_service";
package DY_serviceservice;
// 定义服务
service Calculator {
rpc Get_result (AddRequest) returns (AddResponse);
}
// 请求消息,包含两个参数
message AddRequest {
string fullUrl = 1;
string method = 2;
}
// 响应消息
message AddResponse {
string result = 1;
}
3.2文件字段解释
syntax = "proto3";
// 使用 Protocol Buffers 第3版语法option csharp_namespace = "DY_service";
// 生成的C#代码的命名空间package DY_serviceservice;
// 包名(防止命名冲突)Calculator:
服务名称,客户端通过它调用方法。Get_result:
远程方法名,用于计算 。AddRequest:
输入参数类型。AddResponse:
返回结果类型。
3.3搭建C#服务端
3.3.1.创建WinForms项目
3.3.2添加NuGet包
- 在项目中安装以下NuGet包:
- Grpc.AspNetCore (包含服务器和客户端库)
- Google.Protobuf (ProtoBuf消息处理)
- Grpc.Tools (代码生成工具)
3.3.3添加.proto文件
- 在项目中添加3.1的proto文件
3.3.4配置.proto文件生成
-
右键.proto文件 → 属性 → 设置:
-
生成操作:Protobuf compiler
-
gRPC Stub Classes:Server only
3.3.5实现gRPC服务
创建类CalculatorService.cs:
csharp
using DY_service;
using Grpc.Core;
using Microsoft.Extensions.Logging;
namespace DY
{
public class CalculatorService : Calculator.CalculatorBase
{
private readonly ILogger<CalculatorService> _logger;
public CalculatorService(ILogger<CalculatorService> logger)
{
_logger = logger;
}
public override async Task<AddResponse> Get_a_bogus(AddRequest request, ServerCallContext context)
{
try
{
// 直接 await 异步调用,无需 Task.Run
string result = await Form1.CallJavaScriptFunction(request.FullUrl, request.Method);
return new AddResponse { Result = result };
}
catch (Exception ex)
{
// 记录错误并返回空响应(或自定义错误响应)
Console.WriteLine($"gRPC 调用失败: {ex.Message}");
return new AddResponse { Result = "ERROR: " + ex.Message };
}
}
}
}
这里的Get_a_bogus
方法就是你标准中定义的方法DY_service
是标准中的命名空间。然后还有定义的参数,都是和标准文件中一样。
4. 启动gRPC服务器
在Form1的代码中(例如窗体加载事件):
csharp
private IHost _grpcHost;
private void Form1_Load(object sender, EventArgs e)
{
_grpcHost = Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.UseUrls("http://localhost:5000");
// Program.cs
webBuilder.ConfigureKestrel(options =>
{
options.ListenLocalhost(5000, o => o.Protocols = HttpProtocols.Http2);
});
})
.Build();
Task.Run(() => _grpcHost.Start()); // 在后台线程启动
}
private async void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
if (_grpcHost != null)
{
try
{
// 最多等待 3 秒
await _grpcHost.StopAsync(TimeSpan.FromSeconds(3));
}
catch (Exception ex)
{
Debug.WriteLine($"gRPC 服务器停止失败: {ex.Message}");
}
finally
{
_grpcHost.Dispose();
_grpcHost = null; // 防止重复释放
}
}
//this.Close(); // 关闭窗口
//Application.Exit(); // 结束进程
}
添加Startup.cs类:
csharp
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
namespace DY
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddGrpc();
}
public void Configure(IApplicationBuilder app)
{
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<CalculatorService>();
});
}
}
}
然后运行程序,GRPC服务就启动了。具体的代码意思自己参考官方文档。
5.Python客户端测试代码
- 安装grpc包
csharp
pip install grpcio grpcio-tools
把定义好的 .proto 文件复制到py客户端项目根目录执行如下命令
csharp
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. DY__service.proto
只需要把DY_service.proto
改成你自己的文件名就行了,然后会生成2个文件。_pb2.py
和_pb2_grpc.py
这2文件中的代码不要改,直接调用就行。
python
import grpc
import DY_service_pb2
import DY_service_pb2_grpc
def run():
channel = grpc.insecure_channel('localhost:5000')
stub = DY_service_pb2_grpc.CalculatorStub(channel)
response = stub.Get_resut(DY_service_pb2.AddRequest(fullUrl="https://www.dy.com", method="GET"))
print(f"结果: {response.result}") # 应该输出 结果
if __name__ == '__main__':
run()
这样就可以实现基础通信了 直接调用远程方法,总体还是挺方便。