5
2

More than 1 year has passed since last update.

Go+gRPCでシンプルなEchoサーバ(令和最新版)

Last updated at Posted at 2021-10-12

はじめに

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