Elsaの技術日記(徒然なるままに)

主に自分で作ったアプリとかの報告・日記を記載

MENU

PythonでgRPCを試してみる

今回はPythonでgRPCを試してみたので備忘録をまとめておこうと思います!!
ちょっとgRPCを使うことになったのですが、少し理解できなかったところもあったので試しに動かしてみた感じです。



■gRPCとは?

gRPCはクライアントアプリケーション内のローカルオブジェクトであるかのように、
別マシンに存在するサーバーアプリケーションのメソッドを直接呼び出すことが出来る仕組みになります。
gRPCを用いることで分散アプリケーションやサービスを容易に作成することが可能になります。

サーバー側ではインターフェースを実装し、gRPCサーバーを実行してクライアントの呼び出しに対して処理を行います。
クライアント側ではサーバーと同じメソッドを提供するスタブがあります。

gRPCではサーバー、クラアイント側にて様々な環境で実行及び通信が行えます。
例えば、C++言語でサーバーを作成しクライアント側でJavaPythonを作成して通信することが可能になります。

PythonでgRPCを使うための環境構築

ではまずは環境構築を行っていきます。
gRPCを使用するにあたり下記コマンドを実行します。

pip3 install grpcio

or

python3 -m pip install grpcio

次に、

pip3 install grpcio-tools

or 

python3 -m pip install grpcio-tools

でgrpcio-toolsをインストールします。
grpcio-toolsは.protoファイルを扱うのに用います。

■gRPCサービス定義していく

ではまず、双方向通信を行うためのサービスの作成を行います。
helloworld.protoの名前でこちらのコードを作成します。

syntax = "proto3";

package sample;

message HelloMessage{
    string name = 1;
    string msg = 2;
}


message ReplyMessage{
    string reply_msg = 1;
}

service SampleService{
    rpc SayHello (HelloRequest) returns (HelloReply) {}
}

こちらですが、

message HelloMessage{
    string name = 1;
    string msg = 2;
}

message ReplyMessage{
    string reply_msg = 1;
}

がサーバーとクライアント間で通信するためのメッセージ用のメソッドになります。
本コードにより、sayHelloメソッドでクライアントからHelloRequestを受け取り、サーバーからHelloReplyを返すサービスが生成されます。

ではこちらのコードからprotocol bufferに変換するために下記を実行します。

python3 -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. ./helloworld.proto

本コードを実行することにより、
・helloworld_pb2.py
・helloworld_pb2_grpc.py
が生成されるかと思います。

■サーバーサイド実装

ではサーバーサイド側を実装していきます。

import grpc
import helloworld_pb2
import helloworld_pb2_grpc

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


def serve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
    server.add_insecure_port('[::]:50051')
    server.start()
    server.wait_for_termination()


if __name__ == '__main__':
    serve()

まず、

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

でクライアントから受け取るメソッドを実装します。
その後、

def serve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)

でメソッドを登録し、

    server.add_insecure_port('[::]:50051')
    server.start()
    server.wait_for_termination()

で50051ポートでサーバーを起動しクライアントからのリクエストを待ちます。

■クライアントサイド実装

次にクライアントサイドを実装していきます。

コードはこちら。

import grpc
import helloworld_pb2
import helloworld_pb2_grpc

def run():
    with grpc.insecure_channel('localhost:50051') as channel:
        stub = helloworld_pb2_grpc.GreeterStub(channel)
        response = stub.SayHello(helloworld_pb2.HelloRequest(name='you'))
    print("Greeter client received: " + response.message)


if __name__ == '__main__':
    run()

サーバー側と結構似ていますね。

with grpc.insecure_channel('localhost:50051') as channel:

にて通信を確立し、

stub = helloworld_pb2_grpc.GreeterStub(channel)

でスタブを作成し、生成したスタブからサーバー側へリクエストとしてSayHelloメソッドを送信します。

response = stub.SayHello(helloworld_pb2.HelloRequest(name='you'))

■実際に動かしてみる
では、実際に動かしてみます。
サーバー側を、

python3 サーバーファイル名.py

と実行した後に、
クライアント側を、

python3 クライアントファイル名.py

と実行するとクライアント側で

Greeter client received: Hello, you!

と出力されるかと思います。

■最後に

今回はPythonでgRPCの基礎に関してまとめてみました。
gRPCは大きなシステムになった時にモジュール間で接続するのに役立ちそうだな。
ちょっと使っていこうかな!!

後、このブログを書いてる途中で普段使いのラズパイ3が故障した。。。
これから修理に入ります泣。