Python で gRPC を試す


gRPC をインストール

まずは gRPC をインストールします。
gRPCと共に、RPCのシリアライゼーションを担う Protocol Buffers もインストールされるようです。

$ curl -fsSL https://goo.gl/getgrpc | bash -s python

もし、インストール中に以下のようなエラーが出た場合は homebrew が古いので brew update を試してみてください。(Macの場合)

Error: undefined method `desc' for Grpc:Class
Please report this bug:
    http://git.io/brew-troubleshooting
/usr/local/Library/Taps/grpc/homebrew-grpc/Formula/grpc.rb:2:in `<class:Grpc>'
・・・

.proto(IDL)を書く

Protocol Buffers のIDLを書きます。
以下の例ではサーボを動かすRPCを定義しています。

gRPC 自体は Protocol Buffers のプラグインとなっています。
(gRPC 以外にも RPC 実装はたくさんあります)

gateway.proto
syntax = "proto3";

package gateway;

message MoveServoRequest {
  int32 servo_id = 1;
  int32 position = 2;
}

message MoveServoResponse {
  int32 current_position = 1;
}

service AVRGateway {
  rpc MoveServo (MoveServoRequest) returns (MoveServoResponse) {}
}

IDLをコンパイルしてgRPCのpythonスクリプトを生成

以下の protoc コマンドで、gateway_pb2.py が生成されます。

$ protoc --python_out=. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_python_plugin` gateway.proto

gRPC用のサーバ/クライアントのコードを書く

上記のコマンドで生成されたPythonスクリプトをインポートすれば簡単にサーバ/クライアントが書けます。
gRPCのPythonライブラリ自体まだAlpha版なので、いろんなメソッドにearly_adopter_*というプレフィックスがついています。

gateway_server.py
import time
import gateway_pb2

class AVRGateway(gateway_pb2.EarlyAdopterAVRGatewayServicer):
  def MoveServo(self, request, context):
    print 'servo_id: %d, position: %d' % (request.servo_id, request.position)
    return gateway_pb2.MoveServoResponse(current_position=150)

def serve():
  server = gateway_pb2.early_adopter_create_AVRGateway_server(AVRGateway(), 9494, None, None)
  server.start()
  try:
    while True:
      time.sleep(100000)
  except KeyboardInterrupt:
    server.stop()

if __name__ == '__main__':
  serve()
gateway_client.py
import gateway_pb2

def run():
  with gateway_pb2.early_adopter_create_AVRGateway_stub('localhost', 9494) as stub:
    response = stub.MoveServo(gateway_pb2.MoveServoRequest(servo_id=1, position=200), 10) 
    print "current position: " + str(response.current_position)

if __name__ == '__main__':
  run()

実行

まずサーバを立ち上げます。

$ ls
gateway.proto      gateway_client.py  gateway_pb2.py      gateway_server.py
$ python gateway_server.py

そして別のターミナルでクライアントを。

$ python gateway_client.py
current position: 150
D0729 10:42:14.835677000 140735135564544 iomgr.c:119] Waiting for 1 iomgr objects to be destroyed and executing final callbacks

サーバのほうでは

$ python gateway_server.py 
servo_id: 1, position: 200

という感じで出力されていればOK。