LoginSignup
0
0

More than 3 years have passed since last update.

gRPCで二分木を送信する[Go]

Last updated at Posted at 2020-12-10

インストール

必要なツールをインストールする。

PROTOC_ZIP=protoc-3.7.1-linux-x86_64.zip
curl -OL https://github.com/protocolbuffers/protobuf/releases/download/v3.7.1/$PROTOC_ZIP
sudo unzip -o $PROTOC_ZIP -d /usr/local bin/protoc
sudo unzip -o $PROTOC_ZIP -d /usr/local 'include/*'
rm -f $PROTOC_ZIP

プロジェクトを初期化しgo.modを作る。

go mod init
go get google.golang.org/protobuf/cmd/protoc-gen-go \
         google.golang.org/grpc/cmd/protoc-gen-go-grpc

上でprotoc-gen-go-grpcがインストールできなかったら下記を実行

go get -u -v google.golang.org/grpc/cmd/protoc-gen-go-grpc@master

go.modに各ライブラリが追加されている。

go.mod
module github.com/Asuha-a/grpc-go-test

go 1.15

require (
    google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.0.0 // indirect
    google.golang.org/protobuf v1.25.0 // indirect
)

protoファイルの作成

pbディレクトリに入れておく。

$ tree
.
├── go.mod
├── go.sum
├── Makefile
└── pb
    └── node.proto


node.proto
syntax = "proto3";

option go_package = "github.com/Asuha-a/go-qiita/pb";

package node;

service Node {
  rpc GetBinaryTree (GetBinaryTreeRequest) returns (GetBinaryTreeReply) {}
}

message node {
  int32 index = 1;
  node right = 2;
  node left = 3;
}

message GetBinaryTreeRequest {
  int32 id = 1;
}

message GetBinaryTreeReply {
  int32 id = 1;
  node root = 2;
}

上記のようにnodeのmessageを再帰的に呼び出すことで二分木を定義する。

次のコマンドでpbファイルを作成できる。

protoc --go_out=. --go_opt=paths=source_relative \
    --go-grpc_out=. --go-grpc_opt=paths=source_relative \
    pb/node.proto

いちいち打つのは面倒なのでMakefileを作る。

Makefile
.PHONY: setup
setup:
    protoc --go_out=. --go_opt=paths=source_relative \
        --go-grpc_out=. --go-grpc_opt=paths=source_relative \
        pb/node.proto

.PHONY: clean
clean:
    rm -f pb/node.pb.go
    rm -f pb/node_grpc.pb.go

.PHONY: help
help:
    @echo "setup: setup the envs"
    @echo "clean: delete all files created by make"

コマンドを実行

make setup
protoc-gen-go: program not found or is not executable

が表示された場合は以下を.bashrcもしくは.zshrcに追加してみてほしい。

export GOROOT=/usr/local/go
export GOPATH=$HOME/go
export GOBIN=$GOPATH/bin
export PATH=$PATH:$GOROOT:$GOPATH:$GOBIN

サーバの作成

server.go
package main

import (
    "context"
    "log"
    "net"

    "github.com/Asuha-a/go-qiita/pb"
    "google.golang.org/grpc"
)

const (
    port = ":50051"
)

type server struct {
    pb.UnimplementedNodeServer
}

func (s *server) GetBinaryTree(ctx context.Context, in *pb.GetBinaryTreeRequest) (*pb.GetBinaryTreeReply, error) {
    id := in.Id
    data := &pb.Node{
        Index: 5,
        Right: &pb.Node{Index: 7, Right: nil, Left: nil},
        Left:  &pb.Node{Index: 3, Right: nil, Left: nil},
    }
    return &pb.GetBinaryTreeReply{Id: id, Root: data}, nil
}

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

クライアントの作成

client.go
package main

import (
    "context"
    "log"
    "time"

    "github.com/Asuha-a/go-qiita/pb"
    "google.golang.org/grpc"
)

const (
    port = ":50051"
)

func main() {
    conn, err := grpc.Dial(port, grpc.WithInsecure(), grpc.WithBlock())
    if err != nil {
        log.Fatalf("did not connect: %v", err)
    }
    defer conn.Close()
    client := pb.NewNodeClient(conn)

    ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    defer cancel()
    r, err := client.GetBinaryTree(ctx, &pb.GetBinaryTreeRequest{
        Id: 1,
    })
    if err != nil {
        panic(err)
    }
    log.Printf("%v", r.Root)
}

完成図

$ tree
.
├── client
│   └── client.go
├── go.mod
├── go.sum
├── Makefile
├── pb
│   ├── node_grpc.pb.go
│   ├── node.pb.go
│   └── node.proto
└── server
    └── server.go

3 directories, 8 files

動作検証

サーバを起動したのちにクライアントを実行。

$ go run ./server/server.go

$ go run ./client/client.go                                                                           
2020/12/10 21:09:55 index:5 right:{index:7} left:{index:3} 

無事受け取れた。

0
0
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
0
0