Python如何实现跨语言提供服务?

2022-04-18 15:42:47 浏览数 (1)

大家好,我是Kuls。

最近总算是有时间来给大家写写文章了。

不知道大家有没有接触过RPC框架,RPC的全称是 Remote Procedure Call 即远程过程调用。

如果不理解也没关系,可以看到下图:

假设有两个服务器,上面有两个服务。服务器2中的LoginService想要去调用服务器1中的UserService,那么该如何实现呢?

这时我们就可以使用RPC框架来进行实现,能够像调用本地方法一样来调用远程的方法。

这是网上非常经典的讲解RPC原理的图,大家可以自行琢磨琢磨。

我们今天的主题是教大家如何使用gRPC来实现跨语言调用。

那么gRPC又是啥玩意呢?

就是我上面所说的RPC框架,gRPC是一个很有名的开源RPC框架,它是由谷歌发起的。目前也有非常多的大公司在使用gRPC。

gRPC can use protocol buffers as both its Interface Definition Language (IDL) and as its underlying message interchange format.

上面是gRPC官网给的介绍。

今天给大家演示一下如何用.NET来调用Python中写的服务方法。

我们先来写Python这边的服务:

首先安装好相应的库grpcio

代码语言:javascript复制
python -m pip install grpcio

再来安装grpcio-tools,它能够帮助我们去编译写的proto文件。

代码语言:javascript复制
python -m pip install grpcio-tools

安装完成后,我们来编写proto。

服务端编写

这里可能很多朋友都不知道proto是个啥,它其实是另一门语言,用来编写我们需要提供的服务接口的。

gRPC也正是通过proto来使双边的接口一致。

这里给大家一份语法学习的网站,非常的简单,十分钟上手。

https://colobu.com/2017/03/16/Protobuf3-language-guide/

我们创建一个proto的文件夹,然后创建hello.proto文件

代码语言:javascript复制
syntax = "proto3";   //定义语法版本

// 定义命名空间
option csharp_namespace = "HelloService"; 
//定义包
package greet;

// 定义Greeter服务
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply);
}

// SayHello方法中的参数实体定义
message HelloRequest {
  string name = 1;   // 定义实体中的字段,1代表字段的编号,多个字段编号不能相同
}

// SayHello方法的响应实体定义
message HelloReply {
  string message = 1;
}

编写完后,我们在命令行中输入

代码语言:javascript复制
python -m grpc_tools.protoc -I proto --python_out=. --grpc_python_out=. proto/hello.proto

你可以看到生成了两个文件

这两个文件就是grpc-tools帮助我们编译hello.proto的输出文件。

这两个文件非常重要,我们后面需要用到它。

把我们接口定义完了,接下来就来编写具体的服务了。

我们创建main.py

代码语言:javascript复制
from concurrent import futures
import logging

import grpc
import hello_pb2
import hello_pb2_grpc


class Greeter(hello_pb2_grpc.GreeterServicer):

    def SayHello(self, request, context):
        return hello_pb2.HelloReply(message='Hello, %s!' % request.name)


def serve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    # 可以理解为把服务注册
    hello_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
    server.add_insecure_port('[::]:50051')
    server.start()
    server.wait_for_termination()


if __name__ == '__main__':
    logging.basicConfig()
    serve()

可以看到我们在服务中定义了SayHello方法,然后在server()中开启了端口来让客户端即调用方通过该端口来对我们的方法进行调用。

如果我们客户端调用SayHello方法,就会在控制台输出 Hello xxxxxxcx

客户端编写

这里我们的客户端采用.NET来编写,客户端的编写十分的简单,且支持的语言非常的多。

首先,我们也需要在客户端建一个与服务端一模一样的proto,必须一样哦!

这里的一样指的是proto文件内容,文件名可以不一致,但是建议是一致的。

我们直接编写客户端代码:

代码语言:javascript复制
using Grpc.Net.Client;
using GrpcService1;
using static GrpcService1.Greeter;

namespace GrpcClientDemo
{
    internal class Program
    {
        static void Main(string[] args)
        {
            #region 创建客户端
            GrpcChannel grpcChannel = GrpcChannel.ForAddress("http://localhost:50051"); //(注意确保服务的地址正确)
            GreeterClient greeterClient = new GreeterClient(grpcChannel);
            #endregion

            #region 调用服务
            HelloReply helloReply = greeterClient.SayHello(new HelloRequest()
            {
                Name = "张三"
            });
            #endregion
            Console.WriteLine(helloReply.Message);
        }
    }
}

这里我们传输进去了一个HelloRequest对象,也就是我们在proto文件中定义的,传输过去的Name属性为“张三”。ForAddress中的地址就是我们服务端的地址。

运行一下,看效果。

可以看到我们成功的实现了跨语言的服务调用,不知道大家有没有学fei。

好了,今天的文章就到这,我是kuls,大家记得给个在看呀!

0 人点赞