gRPC Quick Start

gRPC 在工作中有接触,但是自己还没有亲手实践过,确实有待加强。九层之台起于垒土,先写 python 的 hello world 吧。

1 基于 python 的 gRPC hello world

1.1 准备工作

创建虚拟环境并激活,我这里用pyenv

1
2
3
$ pyenv virtualenv -p python3 grpc_learn_env
$ pyenv shell grpc_learn_env
$ pyenv -m pip install --upgrade pip

1.2 安装gRPC

1
$ python -m pip install grpcio

1.3 安装 gRPC tools

1
$ python -m pip install grpcio-tools

1.4 下载案例

1
$ git clone -b v1.25.0 https://github.com/grpc/grpc

1.5 运行一个 gRPC application

在上一步中下载的代码中,找到examples/python/helloworld/greeter_server.py

1
$ python greeter_server.py

运行客户端

1
2
$ python greeter_client.py
Greeter client received: Hello, you!

1.6 更新 gRPC 服务

由官方文档可知,gRPC 服务是通过 protocal buffers 定义的。
在server和client 的桩代码中,有一个SayHello rpc 方法,该方法以来自客户端的HelloRequest作为参数输入,并返回从服务端的HelloReply。代码如下:

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
// Copyright 2015 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";

package helloworld;

// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
string name = 1;
}

更新Greeter服务,使其拥有两个方法,就是复制一下SayHello方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
// Sends another greeting
rpc SayHelloAgain (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
string name = 1;
}

// The response message containing the greetings
message HelloReply {
string message = 1;
}

1.7 生成 gRPC 代码

在 example/python/helloworld 路径下,执行如下命令。

1
$ python -m grpc_tools.protoc -I../../protos --python_out=. --grpc_python_out=. ../../protos/helloworld.proto

重新生成 helloworld_pb2.py 和 helloworld_pb2_grpc.py,前者包含生成的请求和响应类,后者包含生成的客户端和服务端类。

1.8 更新并运行application

greeter_server.py

1
2
3
4
5
6
7
8
class Greeter(helloworld_pb2_grpc.GreeterServicer):

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

def SayHelloAgain(self, request, context):
return helloworld_pb2.HelloReply(message='Hello again, %s!' % request.name)
...

greeter_client.py

1
2
3
4
5
6
7
def run():
channel = grpc.insecure_channel('localhost:50051')
stub = helloworld_pb2_grpc.GreeterStub(channel)
response = stub.SayHello(helloworld_pb2.HelloRequest(name='you'))
print("Greeter client received: " + response.message)
response = stub.SayHelloAgain(helloworld_pb2.HelloRequest(name='you'))
print("Greeter client received: " + response.message)

Run the server

1
2
$ python greeter_server.py
$ python greeter_client.py