😺

pythonでgRPC通信をやってみる

2023/05/04に公開

この記事について

gRPC通信に関して知識と経験がない。とりあえずpythonでやってみる。

頭の整理も兼ねて、最もシンプルなgRPC通信でhello worldを返すアプリケーションを書いてみる。

gRPCの利点・詳細・各用語などは他記事などを参考にしてください。

流れ

  1. (諸々の環境構築)
  2. gRPCのAPI定義ファイルであるprotoファイルを作成
  3. protoファイルをコンパイル
  4. サーバー側のpythonファイルを作成
  5. サーバーを叩くクライアント側のpythonファイルを作成
  6. 実行

諸々のコードは下記になる

.
├── Dockerfile
├── README.md
├── docker-compose.yaml
└── src
    ├── client.py
    ├── pb
    │   ├── __init__.py (ちょっとゴニョゴニョしてる)
    │   ├── helloworld_pb2.py
    │   ├── helloworld_pb2.pyi
    │   └── helloworld_pb2_grpc.py
    ├── proto
    │   └── helloworld.proto
    └── server.py

環境構築

dockerで構築

FROM python:3.8-slim

# 今回はpoetryなどは面倒なので使わない
RUN pip install --upgrade pip \
    && pip install grpcio \
    && pip install grpcio-tools

WORKDIR /src

コンテナ内にアクセスするためには下記コマンドを使う

docker exec -it grpc-grpc-demo-1 sh

gRPCのAPI定義ファイルであるprotoファイルを作成

serviceでメソッドをまとめてエンドポイントを作る。
messageで型定義とかをしておく。

syntax = "proto3";

package helloworld;

// エンドポイント定義
service HelloWorldService {
  rpc SayHello (HelloWorldRequest) returns (HelloWorldResponse);
}

// 型定義
message HelloWorldRequest {
}

message HelloWorldResponse {
    string message = 1;
}

protoファイルのコンパイル

dockerのコンテナ内で、下記のコマンドを実行

(-Iの間にスペースいらないんか、、、)

python -m grpc_tools.protoc -I./proto --python_out=./pb --pyi_out=./pb --grpc_python_out=./pb ./proto/helloworld.proto

いろいろ生成される

サーバー側のpythonファイルを作成

生成されたファイルを使いつつ、

  • レスポンスの処理
  • サーバー起動処理

を書く

from concurrent import futures
import grpc
from pb import helloworld_pb2
from pb import helloworld_pb2_grpc

# レスポンスの処理
class Greeter(helloworld_pb2_grpc.HelloWorldServiceServicer):
    def SayHello(self, request, context):
        return helloworld_pb2.HelloWorldResponse(message="hello world")
    
# サーバー起動処理
def serve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    helloworld_pb2_grpc.add_HelloWorldServiceServicer_to_server(Greeter(), server)

    # サーバーの立ち上げ
    server.add_insecure_port('[::]:5001')
    server.start()
    print("server started")
    server.wait_for_termination()
    

if __name__ == '__main__':
    serve()  

サーバーを叩くクライアント側のpythonファイルを作成

生成されたファイルを使いつつ、下記のような形で書く

import grpc
from pb import helloworld_pb2
from pb import helloworld_pb2_grpc

def run():
    with grpc.insecure_channel('localhost:5001') as channel:
        stub = helloworld_pb2_grpc.HelloWorldServiceStub(channel)
        response = stub.SayHello(helloworld_pb2.HelloWorldRequest())
    print("Response: %s" % response.message)

if __name__ == '__main__':
    run()

実行

python server.pyでサーバー側を立てておいて、

別ウィンドウでクライアント側のスクリプトを実行

うまくいってそう

諸々のコード

https://github.com/sugakoji/grpc-python-sample

Discussion