LoginSignup
2
0

More than 1 year has passed since last update.

gRPCに入門してみた

Posted at

参考ドキュメント

必要なツール

環境準備

$mkdir $WORKSPACE
$cd $WORKSPACE
$brew install protobuf
$goenv local 1.19.2
$go mod init grpcexample
$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
$export PATH="$PATH:$(go env GOPATH)/bin" #NOTE: PATHが通ってなければ実施する

gRPCサービス(API)の定義

gRPCサービス(API)は Protocol Buffer で定義する。

$mkdir -p proto/helloworld
$touch ./proto/helloworld/helloworld.proto
// ./proto/helloworld/helloworld.proto
syntax = "proto3";

option go_package = "pkg/helloworld";

package helloworld;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}

gRPCコードの生成

作成したProtファイルをもとにコードを生成する。

$ mkdir -p pkg/helloworld
$ cd proto
$ protoc \
  --go_out=../pkg \
  --go_opt=paths=source_relative \
  --go-grpc_out=../pkg \
  --go-grpc_opt=paths=source_relative \
  helloworld.proto

サーバコードの実装

$mkdir server
$touch server/main.go
// ./server/main.go
package main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"net"

	pb "grpcexample/pkg/helloworld"

	"google.golang.org/grpc"
)

var (
	port = flag.Int("port", 50051, "The server port")
)

// server is used to implement helloworld.GreeterServer.
type server struct {
	pb.UnimplementedGreeterServer
}

// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
	log.Printf("Received: %v", in.GetName())
	return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}

func main() {
	flag.Parse()
	lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
	s := grpc.NewServer()
	pb.RegisterGreeterServer(s, &server{})
	log.Printf("server listening at %v", lis.Addr())
	if err := s.Serve(lis); err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
}

クライアントコードの実装

$mkdir client
$touch client/main.go
package main
// ./client/main.go
import (
	"context"
	"flag"
	"log"
	"time"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	pb "google.golang.org/grpc/examples/helloworld/helloworld"
)

const (
	defaultName = "world"
)

var (
	addr = flag.String("addr", "localhost:50051", "the address to connect to")
	name = flag.String("name", defaultName, "Name to greet")
)

func main() {
	flag.Parse()
	// Set up a connection to the server.
	conn, err := grpc.Dial(*addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()
	c := pb.NewGreeterClient(conn)

	// Contact the server and print out its response.
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	r, err := c.SayHello(ctx, &pb.HelloRequest{Name: *name})
	if err != nil {
		log.Fatalf("could not greet: %v", err)
	}
	log.Printf("Greeting: %s", r.GetMessage())
}

goの依存モジュールの解決

$go mod tidy

サーバ起動

$go run server/main.go
2023/01/19 17:22:34 server listening at [::]:50051

クライアント実行

(*別プロセスで実行)

$go run client/main.go
2023/01/19 17:23:35 Greeting: Hello world

gRPCのクライアントツールを使う場合

サーバーリフレクションの設定

POSTMANやgrpcurlなどのクライアントツールを使う場合、gRPCサーバからサービス情報を取得することによって実行することができる。サービス情報を取得するにはサーバの設定が必要となる。サーバのコードに以下を追記する。

import (
.
"google.golang.org/grpc/reflection"
)

func main() {
  .
  .
  s := grpc.NewServer()
  reflection.Register(s)
  .
  .
}

grpcurl で実行

# サービスリストの取得
$grpcurl -plaintext localhost:50051 list
grpc.reflection.v1alpha.ServerReflection
helloworld.Greeter

# サービスのメソッドリスト取得
$grpcurl -plaintext localhost:50051 list helloworld.Greeter
helloworld.Greeter.SayHello

# メソッド実行
$grpcurl -plaintext localhost:50051 helloworld.Greeter.SayHello
{
  "message": "Hello "
}

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