gRPCを試してみました。
準備
gRPC試したいだけなら環境は正味なんでもよいと思いますが、今回はラズパイ3でPython製サーバを立ててみます。
まずはPythonの開発環境を整えます。Raspberry Pi OSは標準でPythonが入っていましたが、pipは入っていませんでした。gRPCでの開発に必要なパッケージがpipで入るので、導入しておきます。
$ sudo apt install python3-pip $ python -m pip install --upgrade pip
次に、gRPCのパッケージをインストールします。
$ python -m pip install grpcio $ python -m pip install grpcio-tools
protoの作成
これで準備は整ったので、protoファイルを作成してスタブを生成したのち、サーバ/クライアントのプログラムを作成すればgRPCによるやりとりができるそう。まずはprotoファイルから。sample.protoとして作成しました。
syntax = "proto3"; package sample; service Greeter { rpc SayHello (HelloRequest) returns (HelloReply) {} } message HelloRequest { string name = 1; } message HelloReply { string message = 1; }
GreeterサービスにSayHelloメソッドを持たせます。このメソッドは、string型のnameを持つHelloRequestメッセージを受け取り、同じくstring型のmessageを持つHelloReplyメッセージを返します。
nameやmessageといったフィールドに「=1」とあるのは、代入ではなくタグナンバーの割当てだそうで、数字はメッセージ内で重複してはいけないとのこと。長くプログラムを書いているとnameやmessageに1が入るように錯覚しますね。私は初見でちょっと混乱しました。
サーバ/クライアントプログラムで使用するスタブを生成します。今回作成した程度の規模であれば、生成されたPythonファイルもあまり大きくないので、試しに中身を確認してみてもいいかもしれません。
$ python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. ./sample.proto $ ls # 左の2つが生成された sample_pb2_grpc.py sample_pb2.py sample.proto
サーバ側の作成
gRPCにconcurrent.futuresモジュールのThreadPoolExecutorを渡してあげる必要があるので、importを忘れないようにしてください。ファイル名はserver.pyとしました。
from concurrent import futures import grpc import sample_pb2 import sample_pb2_grpc class Sample(sample_pb2_grpc.GreeterServicer): def SayHello(self, request, context): message = "Hello %s." % request.name return sample_pb2.HelloReply(message=message) def run_server(): server = grpc.server(futures.ThreadPoolExecutor(max_workers=5)) sample_pb2_grpc.add_GreeterServicer_to_server(Sample(), server) server.add_insecure_port('[::]:8080') server.start() server.wait_for_termination() if __name__ == '__main__': run_server()
max_workersやポート番号などはお好みで設定してください。なおadd_insecure_port()は平文での接続になるため、SSL/TLSによる暗号化をしたい場合はadd_secure_port()を使うとのこと。こちらは後日改めて試そうと思います。
クライアント側の作成
次にクライアント側を作りますが、ポート番号はサーバ側と一致させ、リクエストの内容(name)はお好みで。ファイル名はclient.pyとしました。
import grpc import sample_pb2 import sample_pb2_grpc def run_client(): with grpc.insecure_channel('localhost:8080') as ch: stub = sample_pb2_grpc.GreeterStub(ch) reply = stub.SayHello(sample_pb2.HelloRequest(name='Bob')) print("Reply: %s" % reply.message) if __name__ == '__main__': run_client()
動作確認
以下でサーバとクライアントをそれぞれ実行します。クライアントは別端末で実行することを推奨します。確認できたらサーバ側はCtrl+Cで停止してください。
# 端末1 $ python ./server.py # 端末2 $ python ./client.py Reply: Hello Bob.