Go言語+gRPCをはじめから丁寧に解説してみた改[ハンズオン]
はじめに
この記事は@ishishowさんの書かれたGo言語+gRPCをはじめから丁寧に解説してみた[ハンズオン]という記事が22年8月にそのまま実施できなかったので、Go1.18で動くように書き換えてみました。Go言語でgRPCに入門してみたかった...という同趣旨の記事も参考にしています。
先に上記記事の閲覧からお願い致します。
ハンズオン ~Golang~
Mac想定で書きます。
最終的にこのようなディレクトリ構造になります。
.
├── chat
│ ├── chat.go
│ ├── chat.pb.go
│ ├── chat.proto
│ └── chat_grpc.pb.go
├── client
│ └── client.go
├── go.mod
├── go.sum
└── server.go
準備
- Protocol Buffers v3 をインストール
brew install protobuf
- Goのプロトコルコンパイラプラグインをインストール
QuickStart
go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2
- Goのプロジェクトを作成
※GoのPATHも通しておくこと。
export PATH="$PATH:$(go env GOPATH)/bin"
作成
/grpc-go-test
というディレクトリを作ります。これをプロジェクトとファイルとします。
/grpc-go-test
で下記コマンドを実行します。
go mod init grpc-go-test
go mod init コマンドは、Goのモジュールを初期化するためのコマンドです。モジュールとは、Goのパッケージをバージョン管理するための単位で、複数のパッケージを含むことができます。
具体的には、 go mod init コマンドは、現在のディレクトリをルートとする新しいモジュールを作成し、go.mod ファイルを作成します。go.mod ファイルは、そのモジュールの依存関係とバージョンを記録するために使用されます。
1. protoの作成
GoのgRPCコードを自動生成するためのprotoファイルを作ります。
protoファイルはProtocol Buffersの定義ファイルです。
/chat
ディレクトリを作り、そこにchat.proto
を作ります。
/chat/chat.proto
syntax = "proto3";
package chat;
option go_package="./chat";
message Message {
string body = 1;
}
service ChatService {
rpc SayHello(Message) returns (Message) {}
}
2. protoの実行
chat
ディレクトリを作って下記を実行。
protoc --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
./chat/chat.proto
/chat
にchat.pb.go
とchat_grpc.pb.go
が生成されます。
これらはProtocol BuffersメッセージとgRPCサービスを実装するためのGoコードです。
生成されたGoコードは、Protocol BuffersメッセージとgRPCサービスを定義するための構造体、インターフェイス、メソッドなどを含みます。
これらのファイルを自分のGoアプリケーションにインポートすることで、Protocol BuffersメッセージとgRPCサービスを使用することができます。
3. サーバー側のコードを書く
メインとなるサーバー側のコードを書く。
- メッセージを読み取って返すメソッドを定義
/chat/chat.go
package chat
import (
"context"
"log"
)
type Server struct {
UnimplementedChatServiceServer
}
func (s Server) SayHello(ctx context.Context, in *Message) (*Message, error) {
log.Printf("Receive message body from client: %s", in.Body)
return &Message{Body: "Hello From the server"}, nil
}
- サーバーの処理を書く
/server.go
package main
import (
"grpc-go-test/chat"
"google.golang.org/grpc"
"log"
"net"
)
func main() {
lis, err := net.Listen("tcp", ":9000")
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := chat.Server{}
grpcServer := grpc.NewServer()
chat.RegisterChatServiceServer(grpcServer, &s)
if err := grpcServer.Serve(lis); err != nil {
log.Fatalf("failed to serve: %s", err)
}
}
コードを書き終わったら、
go mod tidy
を実行して、必要なパッケージをインストールします。
4. サーバー起動
go run server.go
これでサーバーが起動します。
5. サーバーを叩く
サーバーと通信するクライアントを作ります。
client/client.go
(どこかにclient.goを作って!)
package main
import (
"grpc-go-test/chat"
"context"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"log"
)
func main() {
var conn *grpc.ClientConn
conn, err := grpc.Dial(":9000", grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatalf("did not connect: %s", err)
}
defer conn.Close()
c := chat.NewChatServiceClient(conn)
resp, err := c.SayHello(context.Background(), &chat.Message{
Body: "Hello From Client!",
})
if err != nil {
log.Fatalf("Error when calling SyaHello: %s", err)
}
log.Printf("Responce from server: %s", resp.Body)
}
サーバーを起動した状態で
go run client.go
実行すると
2022/08/21 21:51:37 Responce from server: Hello From the server
みたいに帰ってきて、サーバーからレスポンスが帰ってきます。
サーバー側を見てみると
2022/08/21 21:51:37 Receive message body from client: Hello From Client!
とログが表示されています。
GolangでgRPCサーバーの構築とgRPCクライアントの構築ができました。
Discussion