はじめに
Ruby を使って簡単なアプリを作りながら gRPC を練習してみたいと思います。
今回作成するのは計算機のCLIアプリです。
ターミナル上で 1 + 2 などと入力するとクライアントが"1 + 2"の文字列をサーバーへ送信し サーバー側が答えを計算しレスポンスとして返してくれるというものです。
これをgRPCで実装します。
準備
grpc と grpc-tools の gem をインストールします。
$ gem install grpc
$ gem install grpc-tools
アプリ用のディレクトリを作成します。
名前はなんでも良いですがとりあえず grpc_calc とします。
$ mkdir grpc_calc
$ cd grpc_calc
実装
Protocol Buffers を定義する
proto ファイルを作成していきます。
grpc_calc $ mkdir protos
grpc_calc $ vi protos/calc.proto
calc.proto
// この proto ファイルは proto3 の文法で作成します。
syntax = "proto3";
// example というパッケージ名で作ります。(※名前はなんでも良いです。)
package example;
// 計算機のサービスを定義します。
service Calc {
// solve というメソッドを定義します。
// Input を引数に渡すとOutput を返します。
rpc Solve (Input) returns (Output) {}
}
// クライアントから渡す計算式です。
message Input {
// question という名前で文字列を定義します。 タグは1とします。
string question = 1;
}
// サーバー側が返す答えです。
message Output {
// answer という名前で数値を定義します。 タグは1とします。
int32 answer = 1;
}
lib ディレクトリを作ります。
grpc_calc $ mkdir lib
protps/calc.proto をコンパイルし lib 以下に出力します。
grpc_calc $ grpc_tools_ruby_protoc -I protos --ruby_out=lib --grpc_out=lib protos/calc.proto
すると lib以下に calc_pb.rb と calc_services_pb.rb ができていると思います。
サービスの実装
サーバー側から実装していきます。
calc_server.rb
require 'grpc'
require_relative 'lib/calc_services_pb.rb'
class CalcServer < Example::Calc::Service
def solve(input, _unused_call)
answer = eval(input.question)
return Example::Output.new(answer: answer)
end
end
def main
s = GRPC::RpcServer.new
s.add_http2_port('0.0.0.0:50051', :this_port_is_insecure)
s.handle(CalcServer)
s.run_till_terminated_or_interrupted([1, 'int', 'SIGQUIT'])
end
main
クライアント側も実装していきます。
calc_client.rb
require 'grpc'
require_relative 'lib/calc_services_pb.rb'
def main(input)
stub = Example::Calc::Stub.new('localhost:50051', :this_channel_is_insecure)
output = stub.solve(Example::Input.new(question: input))
p "答えは #{output.answer}"
end
p "計算式を書いてください"
input = gets.chomp
main(input)
これで実装は終了です。
実際に動かしてみる
サーバー起動
grpc_calc $ ruby calc_server.rb
クライアント実行
grpc_calc $ ruby calc_client.rb
"計算式を書いてください"
10 + 20 + 30
"答えは 60"
上記のようになれば成功です!