goとpythonで始めるgRPCの事始め


gRPCってなんだって思って調べてたら実装してしまっていたので備忘録として残します。

## ゴール

このようなディレクトリ構造でpythonクライアントとgoサーバー間でgRPCを実装していくことをゴールとします.

```
$GOPATH/src/pygo-grpc/
  ├ client/
  | ├ app.py
  | ├ hello_pb2_grpc.py　　　　　(gRPC自動生成)
  | └ hello_pb2.py　　　　　　　　(gRPC自動生成)
  ├ protos/
  | └ hello.protc
  └ server/
    ├ grpc-server/hello.pb.go　(gRPC自動生成)
    └ server.go
```
## プロトコルを定義

- `$GOPATH`の配下に新しいワーキングディレクトリを作成し、プロトコルを定義します。

```
~ $ cd $GOPATH/src
src $ mkdir pygo-grpc;cd $_
pygo-grpc $ mkdir client protocs server server/grpc-server
pygo-grpc $ touch protocs/hello.proto
```
##### protocs/hello.proto
```protobuf

syntax = "proto3";

package hello;

service Hello {
  rpc PushMsg (MsgStruct) returns (MsgStruct) {}
}

message MsgStruct {
  string message = 1;
}
```
パラメータ、戻り値、呼び出しメソッドを定義しています。
今回は簡単なメッセージの通信を実装するので、`PushMsg`というメソッドを定義し、そのパラメータと戻り値をどちらも同じ`MsgStruct`で定義します。

## GoでgRPCサーバーを実装する

### GoのgRPC周りのインストール
まだの人はチャチャッとやってしまいましょう。

```
go version // 1.6以上必要
go get -u google.golang.org/grpc // Install gRPC
go get -u github.com/golang/protobuf/protoc-gen-go // Install the protoc plugin
```
### GoのgRPCコードを生成
protoファイルの場所とgRPCコードを生成する場所を指定。

```
pygo-grpc $ protoc -I protocs/ protocs/hello.proto --go_out=plugins=grpc:server/grpc-server/
```
`server/grpc-server/hello.pb.go`が自動生成されます。
### GoのgRPCサーバー実装
```
pygo-grpc $ touch server/server.go
```
##### server/server.go
```go
package main

import (
	"context"
	"log"
	"net"

	"google.golang.org/grpc"
	pb "pygo-grpc/server/grpc-server"
)

const (
	port = ":50051"
)

type server struct {
	pb.UnimplementedHelloServer
}

func (s *server) PushMsg(ctx context.Context, p *pb.MsgStruct) (*pb.MsgStruct, error) {
	log.Printf("Received: %v", p.Message)
	return &pb.MsgStruct{Message: "Hello " + p.Message}, nil
}

func main() {
	lis, err := net.Listen("tcp", port)
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
	s := grpc.NewServer()
	pb.RegisterHelloServer(s, &server{})
	if err := s.Serve(lis); err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
}

```
## PythonでgRPCクライアントを実装する
### pythonの仮想環境の立ち上げ
```
pygo-grpc $ virtualenv venv && source venv/bin/activate
```
venvはトレースしなくて大丈夫なので .gitignoreにでも
### PythonのgRPC周りのインストール
```
(venv) pygo-grpc $ pip install grpcio
(venv) pygo-grpc $ pip install grpcio-tools
```
### PythonのgRPCコードを生成
```
(venv) pygo-grpc $ python -m grpc_tools.protoc -I protocs --python_out=client --grpc_python_out=client protocs/hello.proto
```
`client/hello_pb2_grpc.py` と `client/hello_pb2.py` が自動生成されます

### PythonのgRPCクラアイアント実装
##### client/app.py
```python
from __future__ import print_function
import logging

import grpc

import hello_pb2
import hello_pb2_grpc


def run():
  msg = input()
  with grpc.insecure_channel('localhost:50051') as channel:
      stub = hello_pb2_grpc.HelloStub(channel)
      stub.PushMsg(hello_pb2.MsgStruct(message=msg))

if __name__ == '__main__':
    logging.basicConfig()
    run()
```
## 動作確認
まずサーバーを立ち上げ

```
pygo-grpc $ go run server/server.go
```
次にクライアントを立ち上げます

```
(venv) pygo-grpc $ python client/app.py
```

![画面収録 2019-10-31 19.15.00.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235435/a1cc8cc5-e4d0-1ad0-84a5-b1a449cefaab.gif)

うまくいきました😆

[written by tomowarkar](https://tomowarkar.com)


### 参考
https://grpc.io/docs/quickstart/go/
https://grpc.io/docs/quickstart/python/