LoginSignup
2
4

More than 5 years have passed since last update.

自分用gRPCメモ

Last updated at Posted at 2019-01-08

リポジトリ

メモ

説明

こんな感じのprotobufを書く

helloworld.proto
syntax = "proto3";

package helloworld;

service World {
  rpc sayHello(RequestType) returns (ResponseType) {};
}

message RequestType {
}

message ResponseType {
  string message = 1;
}
$ protoc -I. --python_out=. --grpc_python_out=./server/python ./proto/helloworld.proto

これをpythonをtargetに生成するとprotocすると (protocはprotobuf compileの略っぽい

  • helloworld_pb2.py
  • helloworld_pb2_grpc.py

の2つのファイルが生成される
この2つのファイルがなんなのかというと、pb2の方がリクエストとレスポンスのクラス定義が入っている。
pb2_grpcの方には、クライアントとサーバーのクラス定義が入っている。

生成される中身はこんな感じ (生成ファイルは.gitignoreするのが吉みたい

helloworld_pb2_grpc.py
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
import grpc

from proto import helloworld_pb2 as proto_dot_helloworld__pb2


class WorldStub(object):
  # missing associated documentation comment in .proto file
  pass

  def __init__(self, channel):
    """Constructor.

    Args:
      channel: A grpc.Channel.
    """
    self.sayHello = channel.unary_unary(
        '/helloworld.World/sayHello',
        request_serializer=proto_dot_helloworld__pb2.RequestType.SerializeToString,
        response_deserializer=proto_dot_helloworld__pb2.ResponseType.FromString,
        )


class WorldServicer(object):
  # missing associated documentation comment in .proto file
  pass

  def sayHello(self, request, context):
    # missing associated documentation comment in .proto file
    pass
    context.set_code(grpc.StatusCode.UNIMPLEMENTED)
    context.set_details('Method not implemented!')
    raise NotImplementedError('Method not implemented!')


def add_WorldServicer_to_server(servicer, server):
  rpc_method_handlers = {
      'sayHello': grpc.unary_unary_rpc_method_handler(
          servicer.sayHello,
          request_deserializer=proto_dot_helloworld__pb2.RequestType.FromString,
          response_serializer=proto_dot_helloworld__pb2.ResponseType.SerializeToString,
      ),
  }
  generic_handler = grpc.method_handlers_generic_handler(
      'helloworld.World', rpc_method_handlers)
  server.add_generic_rpc_handlers((generic_handler,))
helloworld_pb2.py
# Generated by the protocol buffer compiler.  DO NOT EDIT!
# source: proto/helloworld.proto

import sys
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)

_sym_db = _symbol_database.Default()




DESCRIPTOR = _descriptor.FileDescriptor(
  name='proto/helloworld.proto',
  package='helloworld',
  syntax='proto3',
  serialized_options=None,
  serialized_pb=_b('\n\x16proto/helloworld.proto\x12\nhelloworld\"\r\n\x0bRequestType\"\x1f\n\x0cResponseType\x12\x0f\n\x07message\x18\x01 \x01(\t2H\n\x05World\x12?\n\x08sayHello\x12\x17.helloworld.RequestType\x1a\x18.helloworld.ResponseType\"\x00\x62\x06proto3')
)




_REQUESTTYPE = _descriptor.Descriptor(
  name='RequestType',
  full_name='helloworld.RequestType',
  filename=None,
  file=DESCRIPTOR,
  containing_type=None,
  fields=[
  ],
  extensions=[
  ],
  nested_types=[],
  enum_types=[
  ],
  serialized_options=None,
  is_extendable=False,
  syntax='proto3',
  extension_ranges=[],
  oneofs=[
  ],
  serialized_start=38,
  serialized_end=51,
)


_RESPONSETYPE = _descriptor.Descriptor(
  name='ResponseType',
  full_name='helloworld.ResponseType',
  filename=None,
  file=DESCRIPTOR,
  containing_type=None,
  fields=[
    _descriptor.FieldDescriptor(
      name='message', full_name='helloworld.ResponseType.message', index=0,
      number=1, type=9, cpp_type=9, label=1,
      has_default_value=False, default_value=_b("").decode('utf-8'),
      message_type=None, enum_type=None, containing_type=None,
      is_extension=False, extension_scope=None,
      serialized_options=None, file=DESCRIPTOR),
  ],
  extensions=[
  ],
  nested_types=[],
  enum_types=[
  ],
  serialized_options=None,
  is_extendable=False,
  syntax='proto3',
  extension_ranges=[],
  oneofs=[
  ],
  serialized_start=53,
  serialized_end=84,
)

DESCRIPTOR.message_types_by_name['RequestType'] = _REQUESTTYPE
DESCRIPTOR.message_types_by_name['ResponseType'] = _RESPONSETYPE
_sym_db.RegisterFileDescriptor(DESCRIPTOR)

RequestType = _reflection.GeneratedProtocolMessageType('RequestType', (_message.Message,), dict(
  DESCRIPTOR = _REQUESTTYPE,
  __module__ = 'proto.helloworld_pb2'
  # @@protoc_insertion_point(class_scope:helloworld.RequestType)
  ))
_sym_db.RegisterMessage(RequestType)

ResponseType = _reflection.GeneratedProtocolMessageType('ResponseType', (_message.Message,), dict(
  DESCRIPTOR = _RESPONSETYPE,
  __module__ = 'proto.helloworld_pb2'
  # @@protoc_insertion_point(class_scope:helloworld.ResponseType)
  ))
_sym_db.RegisterMessage(ResponseType)



_WORLD = _descriptor.ServiceDescriptor(
  name='World',
  full_name='helloworld.World',
  file=DESCRIPTOR,
  index=0,
  serialized_options=None,
  serialized_start=86,
  serialized_end=158,
  methods=[
  _descriptor.MethodDescriptor(
    name='sayHello',
    full_name='helloworld.World.sayHello',
    index=0,
    containing_service=None,
    input_type=_REQUESTTYPE,
    output_type=_RESPONSETYPE,
    serialized_options=None,
  ),
])
_sym_db.RegisterServiceDescriptor(_WORLD)

DESCRIPTOR.services_by_name['World'] = _WORLD

# @@protoc_insertion_point(module_scope)

ではこの生成された定義ファイルを使ってクライアントとサーバーのコードを書いてみます

サーバーのコードを書いてみます

server.py
import time
import grpc
from concurrent import futures
from proto import helloworld_pb2
from proto import helloworld_pb2_grpc

SERVER_IP = '127.0.0.1'
SERVER_PORT = '9999'

class Servicer(helloworld_pb2_grpc.WorldServicer):
  def sayHello(self, request, context):
      print('hello from server')
      return helloworld_pb2.ResponseType(message='hello world')


def serve():
    print('Starting server...')
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    helloworld_pb2_grpc.add_WorldServicer_to_server(
        Servicer(), server
    )
    server.add_insecure_port(SERVER_IP + ':' + SERVER_PORT)
    server.start()
    print('Listen :' + SERVER_PORT)
    try:
        while True:
            time.sleep(3600)
    except KeyboardInterrupt:
        print('Stop server')
        server.stop(0)


if __name__ == '__main__':
    serve()

Servicerがserviceを定義するもの。 (クラス、メソッドモジュールみたいなもの
で、サービサーをサーバーに追加してます。
プロセスが死なないように無限ループ + スリープをしときます。

クライアントのコードを書いてみます

client.py
import grpc
from proto import helloworld_pb2
from proto import helloworld_pb2_grpc

SERVER_IP = '127.0.0.1'
SERVER_PORT = '9999'


def run():
  print('start run')
  channel = grpc.insecure_channel(SERVER_IP + ':' + SERVER_PORT)
  stub = helloworld_pb2_grpc.WorldStub(channel)
  stub.sayHello(helloworld_pb2.RequestType())
  print('sayHello')


if __name__ == '__main__':
  run()
  1. サーバーのチャネルを指定します
  2. helloworld_pb2_grpcにあるStubにチャネルを渡してstub instanceを生成します
  3. sayHelloを実行します。

所管

GRPC良さそう

2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4