見出し画像

gRPCとProtocol Buffersによるアプリケーション間通信 / Python

「gRPC」でアプリケーション間通信を行い、別アプリからテキストと画像を取得するスクリプトを作ります。

1. gRPC

「RPC」は、アプリケーション間通信のひとつで、プログラミングのメソッドを呼び出す手順で、別のプログラムを操作できます。
「gRPC」は、Googleが開発した「RPC」で、高速かつ低容量、様々な言語に対応しています。

gRPC  -  A high performance, open-source universal RPC framework

2. Protocol Buffers

「Protocol Buffers」(protobuf)は、構造化データをシリアライズするインタフェース記述言語のひとつです。「JSON」や「XML」などと比べ、高速かつ低容量で、様々な言語に対応しています。
「protoファイル」で構造化データを定義し、コンパイルすることで各言語のコードを生成します。

Protocol Buffers  |  Google Developers

3. 開発ツールのインストール

Macで「Protocol Buffers」のコンパイラをインストールするコマンドは、次のとおりです。

$ brew install protobuf

Pythonで「gRPC」を実装するためのパッケージ「grpcio-tools」をインストールするコマンドは、次のとおりです。

$ pip install grpcio-tools

4. protoファイルの生成

構造化データを定義する「protoファイル」を生成します。「image」の型は「bytes」もありますが、byte[]で渡せるのがGoのみだったので、シンプルにstringにしてます。

【simple.proto】

syntax = "proto3";

package simple;

//リクエスト
message SimpleRequest{
}

//レスポンス
message SimpleResponse{
  string text = 1;
  string image = 2;
}

//RPCインタフェースの定義
service SimpleService{
  rpc SimpleSend (SimpleRequest) returns (SimpleResponse) {}
}

5. protoファイルのコンパイル

「protoファイル」をコンパイルするには、以下のPythonコードを実行します。

【codegen.py】

from grpc.tools import protoc
protoc.main(
    (
        '',
        '-I.',
        '--python_out=.',
        '--grpc_python_out=.',
        'simple.proto',
    )
)

以下の2つのファイルが生成されます。

simple_pb2.py : シリアライズのインタフェース
simple_pb2_grpc.py : gRPCのインタフェース

6. サーバーの実装

サーバーを実装します。

【simple_server.py】

import time
import grpc
import simple_pb2
import simple_pb2_grpc
import base64
from concurrent import futures

# シンプルサービスサーバーの定義
class SimpleServiceServicer(simple_pb2_grpc.SimpleServiceServicer):
    # 初期化
    def __init__(self):
      pass

    # 受信時の処理
    def SimpleSend(self, request, context):
        text = 'This is TEST!'
        b64 = base64.encodestring(open('image.jpg', 'rb').read()).decode('utf8')
        return simple_pb2.SimpleResponse(text=text, image=b64)

# サーバーの開始
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
simple_pb2_grpc.add_SimpleServiceServicer_to_server(SimpleServiceServicer(), server)
server.add_insecure_port('[::]:50051')
server.start()
print('サーバーの開始')

# 待機
try:
   while True:
      time.sleep(3600)
except KeyboardInterrupt:
   # サーバーの停止
   server.stop(0)

◎ サーバーの処理の実装
「simple_pb2_grpc.SimpleServiceServicer」を継承して、SimpleSend()を実装します。クライアントからの「SimpleRequest」を受信し、それに応じて「SimpleResponse」を返しています。

◎ サーバーの開始
「SimpleServiceServicer」でサーバーを生成し、ワーカー数「10」、ポート番号「50051」を指定して、開始しています。

◎ サーバーの停止
キー割り込みがあった場合は、サーバーを停止しています。

7. クライアントの実装

クライアントを実装します。

【simple_client.py】

import grpc
import simple_pb2
import simple_pb2_grpc
import base64

# サーバーとの接続
with grpc.insecure_channel('localhost:50051') as channel:
    stub = simple_pb2_grpc.SimpleServiceStub(channel)

    # データの取得
    response = stub.SimpleSend(simple_pb2.SimpleRequest())
    print('text:', response.text)
    with open('client.jpg', mode='wb') as f:
        f.write(base64.b64decode(response.image))

◎ サーバーとの接続
サーバーとの接続は、grpc.insecure_channel()でチャンネルを取得し、「SimpleServiceStub」でサーバースタブを生成し、SimpleSend()を呼んでいます。「ChatRequest」を送信し、「ChatResponse」を受信します。

8. サーバーとクライアントの実行

サーバーとクライアントを実行します。サーバー側に「image.jpg」も必要になります。

$ python simple_server.py
$ python simple_client.py

クライアント側でテキストと画像が取得できます。

この記事が気に入ったらサポートをしてみませんか?