使用Go+gRPC构建一个简单的Echo服务器(Reiwa最新版本)

首先

从安装Go开始,一直到使用gRPC实现简单Echo服务的步骤。

安装各种工具

$ 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

protobuf

$ 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

回声服务的实现

创建项目模板

$ 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
广告
将在 10 秒后关闭
bannerAds