はじめに
GoのインストールからシンプルなEchoサービスをgRPCで実装するまでの手順。
各ツールのインストール
Go
$ wget https://golang.org/dl/go1.17.linux-amd64.tar.gz
$ sudo tar xf go1.17.linux-amd64.tar.gz -C /usr/local
$ echo "GOPATH=${HOME}/go" >>.bashrc
$ echo "PATH=${PATH};/usr/local/go/bin" >>.bashrc
$ source .bashrc
protoc
$ wget https://github.com/protocolbuffers/protobuf/releases/download/v3.18.1/protoc-3.18.1-linux-x86_64.zip
$ unzip -d ${HOME}/.local protoc-3.18.1-linux-x86_64.zip
$ echo "PATH=${PATH};${HOME}/.local/bin" >>.bashrc
$ source .bashrc
Goライブラリ
$ go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.26
$ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1
$ go get -u google.golang.org/grpc
Echoサービス実装
プロジェクトの雛形作成
$ mkdir -p myproj
$ mkdir -p myproj/cmd/{client,server}
$ mkdir -p myproj/internal/grpc
$ export PROJ_ROOT=${HOME}/myproj
$ cd ${PROJ_ROOT}
$ go mod init 192.168.0.0/myproj
.proto作成
$ cd ${PROJ_ROOT}
$ vi my.proto
syntax = "proto3";
option go_package = "192.168.0.0/myproj/grpc";
service Echo {
rpc Echo (EchoRequest) returns (EchoReply) {}
}
message EchoRequest {
string body = 1;
}
message EchoReply {
string body = 1;
}
Goコード生成
$ protoc --go_out=./internal/grpc \
--go_opt=paths=source_relative \
--go-grpc_out=./internal/grpc \
--go-grpc_opt=paths=source_relative,require_unimplemented_servers=false my.proto
サーバ実装
$ cd ${PROJ_ROOT}/cmd/server
$ vi main.go
package main
import (
"context"
"log"
"net"
"google.golang.org/grpc"
mygrpc "192.168.0.0/myproj/internal/grpc"
)
type server struct {
}
func (s *server) Echo(ctx context.Context, p *mygrpc.EchoRequest) (*mygrpc.EchoReply, error) {
log.Println("request received")
res := mygrpc.EchoReply{
Body: p.Body,
}
return &res, nil
}
func main() {
lis, err := net.Listen("tcp", "127.0.0.1:9999")
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
grpcServer := grpc.NewServer()
mygrpc.RegisterEchoServer(grpcServer, &server{})
if err := grpcServer.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
クライアント実装
$ cd ${PROJ_ROOT}/cmd/client
$ vi main.go
package main
import (
"context"
"log"
"time"
"google.golang.org/grpc"
mygrpc "192.168.0.0/myproj/internal/grpc"
)
func main() {
conn, err := grpc.Dial("127.0.0.1:9999", grpc.WithInsecure())
if err != nil {
log.Fatalf("connection failed: %v", err)
}
defer conn.Close()
client := mygrpc.NewEchoClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
r, err := client.Echo(ctx, &mygrpc.EchoRequest{Body:"hello"})
log.Println(r)
log.Println("done")
}
動作確認
- サーバ起動
$ cd ${PROJ_ROOT}/cmd/server
$ go run main.go
- クライアント実行
$ cd ${PROJ_ROOT}/cmd/client
$ go run main.go
2021/10/12 18:06:47 body:"hello"
2021/10/12 18:06:47 done