Introduction
前回は導入手順の紹介しました。
C#をサポートしているので、試してみないわけにはいきません。
Pythonもサポートしており、簡単にテストできそうです。
内容としては、C#(クライアント)-Python(サーバー)とし、クライアントから送信した画像をサーバー側で反転して返すというプログラムになります。
今回のソースは下記になります。
Preparation
C#側は前回インストールしましたので省略します。
Python
Pythonにもインストールしておきます。
Pythonインタープリターは、いつも通りMinicondaになります。
pipでインストールする場合は、pipのバージョンが8以降であることが条件です。
バージョンは下記の手順で確認。
1 | C:\Program Files\Miniconda2>python -m pip --version |
gRPCをインストールします。
1 | C:\Program Files\Miniconda2>python -m pip install grpcio |
続いて、gRPC toolsをインストールします。
1 | C:\Program Files\Miniconda2>python -m pip install grpcio-tools |
gRPC toolsは proto というファイルから、サーバー、クライアント側のコードを生成するためのジェネレーターになります。
Source
gRPC tools
protoファイルを用意して、サーバー、クライアントのコードを生成します。
imageProc.proto
サンプルが github にありますが、面白くないので、手を加えます。
1 | syntax = "proto3"; |
続いて、imageProc.protoからコードを生成します。
gRPC toolsから生成しますが、PythonとC#側でそれぞれ生成する必要があります。
また、言語用にそれぞれgRPC toolsがあるので、それぞれ入手します。
for Python
PythonでのgRPC toolsは下記のように使います。
1 | python -m grpc_tools.protoc -I<protoファイルの存在ディレクトリ> --python_out=<出力先のパス> --grpc_python_out=<出力先のパス> <protoファイルのパス> |
今回のソース構成では、gRPC1フォルダにimageProc.protoがありますので、そこをカレントディレクトリにして下記を実行します。
1 | python -m grpc_tools.protoc -I. --python_out=python --grpc_python_out=python imageProc.proto |
これにより、Python\imageProc_pb2.pyとPython\imageProc_pb2_grpc.py が生成されます。
for C#
C#側は少し面倒です。
まず、nugetを入手します。
これはVisual Studioから実行できるものではなく、スタンドアロンのコマンドラインツールです。
Available NuGet Distribution Versionsから、**nuget.exe - recommended latest (v3.5.0)**を選択します。
ダウンロードしたnuget.exeを適切な場所に展開し、ソースフォルダのpackagesフォルダをカレントディレクトにして、次のコマンドを入力します。
1 | D:\Works\Demo\gRPC1\packages>"C:\Program Files\NuGet\nuget.exe" install Grpc.Tools |
カレントディレクトリにGrpc.Tools.1.2.0が作成されます。
続いて、コードを生成します。
構文はPythonと似ています。
1 | protoc.exe -I<protpファイルの存在ディレクトリ> --csharp_out <出力先のパス> --grpc_out <出力先のパス> <protoファイルのパス> --plugin=protoc-gen-grpc=<grpc_csharp_plugin.exeのパス> |
grpc_csharp_plugin.exeは先ほどのnuget.exeでGrpc.Toolsをインストールした際に、同時にインストールされます。
ですので、下記のようにしてimageProc.protoからコードを生成します。
1 | D:\Works\Demo\gRPC1>mkdir gRPC\Contracts D:\Works\Demo\gRPC1>packages\Grpc.Tools.1.2.0\tools\windows_x86\protoc.exe -I. --csharp_out gRPC\Contracts --grpc_out gRPC\Contracts imageProc.proto --plugin=protoc-gen-grpc=packages\Grpc.Tools.1.2.0\tools\windows_x86\grpc_csharp_plugin.exe |
これにより、gRPC\Contracts\ImageProc.csとgRPC\Contracts\ImageProcGrpc.cs が生成されます。
Python
コードの生成が完了したので、Python側でgRPCを利用するコードを記述していきます。
imageProc_server.py
xxx_pb2_grpc.py というファイルにて、クライアント、サービスの基底クラスが定義されていますので、これらから派生したクラスを実装していきます。
Python側がサーバーになるので、ImageProcServicerから派生します。
1 | from concurrent import futures |
ImageProcは自動生成されたImageProcServicerから派生して適宜実装します。
今回は、入力されたバイナリデータを反転する処理を書いています。
main関数はserve関数を呼び出しています。
serve関数は、https://github.com/grpc/grpc/blob/master/examples/python/helloworld/greeter_server.pyを参考に記述しますので簡単です。
C#
MVVMで実装します。
画像ファイルを読み込むボタン、読み込んだ画像を表示するパネル、サーバーと通信するための送信ボタン、サーバーからの結果を表示するためのパネルを備えています。
また、実装を開始する前に、nugetでGoogle.Protobufをインストールします。
MainViewModel.cs
まずは、interfaceです。
Xaml上のButtonに対応するCommandと、Imgaeに対応するImageSourceを備えているだけです。
1 | using System.Windows.Media; |
IMainViewModel.cs
IMainViewModelを継承しています。
1 | using System; |
OpenFileCommandは、画像ファイルをSystem.Windows.Media.Imaging.BitmapImageに変換して、SourceImageに設定するだけです。
注目は、ServerRequestCommandの下記の部分です。
1 | var channel = new Grpc.Core.Channel("127.0.0.1:50051", Grpc.Core.ChannelCredentials.Insecure); |
ローカル(127.0.0.1)のポート50051に対して、gRPCで通信を確立し、APIを呼び出しています。
ImageProc.ImageProc.ImageProcClientは、gRPC toolsで自動生成しているものです。
通信に関係するコードはすべて自動で生成されるので、クライアント側は、ちょっとした呼び出しのコードを記述するだけで、簡単にサーバー側のAPIを呼び出せるわけです。
Test
サーバー側とクライアント側をテストしてみます。
サーバー側(imageProc_server.py)を起動し、任意の画像ファイルを読み込み、サーバー側APIを呼び出すと、反転した画像が返ってきます。
Conclusion
通信周りはすべて自動生成に任せ、ビジネスロジックの実装に注力できるのは、本当に楽です。
今時、ソケットだのコールバックだの考えるのは本当に面倒です。
Source Code
https://github.com/takuya-takeuchi/Demo/tree/master/RemoteProcedureCall/gRPC/01_gRPC1