Go 开发 gRPC 服务端和客户端

154974
2022/08/26 21:55:27

Go 开发 gRPC 需要两个protoc插件和一个代码依赖。

  • 插件:protoc-gen-go:用于将 proto 生成 Go 语言的数据结构
  • 插件:protoc-gen-go-grpc:用于生成 gRPC 相关的代码
  • 代码依赖:google.golang.org/grpc

安装插件

go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

生成代码

mkdir -p ./pb && \
protoc --go_out=./pb --go_opt=paths=source_relative \
--go-grpc_out=./pb --go-grpc_opt=paths=source_relative \
--proto_path=../proto helloworld.proto
protoc --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
pb/helloworld.proto

安装依赖

你可以手动安装依赖:

go get -u google.golang.org/grpc

更推荐的是,使用 go mod 来自动管理依赖:

go mod tidy

服务端

server/main.go中编写服务端代码。

首先,实现自己的 MyGreeter服务:

type MyGreeter struct {
	pb.UnimplementedGreeterServer
}

func (s *MyGreeter) SayHello(c context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
	return &pb.HelloReply{Message: "[Go] Hello " + in.Name}, nil
}

然后,在 main()中启动该服务:

func main() {
	addr := ":9527"
	listen, err := net.Listen("tcp", addr)
	if err != nil {
		log.Fatal("Error listening", err)
		return
	}
	s := grpc.NewServer()
	pb.RegisterGreeterServer(s, &MyGreeter{})
	log.Println("[GO] Server listen at:", addr)
	if err := s.Serve(listen); err != nil {
		log.Fatal("Error Serveing", err)
		return
	}
}

完整代码:

package main

import (
	"context"
	"helloworld_go/pb"
	"log"
	"net"

	"google.golang.org/grpc"
)

type MyGreeter struct {
	pb.UnimplementedGreeterServer
}

func (s *MyGreeter) SayHello(c context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
	return &pb.HelloReply{Message: "[Go] Hello " + in.Name}, nil
}

func main() {
	addr := ":9527"
	listen, err := net.Listen("tcp", addr)
	if err != nil {
		log.Fatal("Error listening", err)
		return
	}
	s := grpc.NewServer()
	pb.RegisterGreeterServer(s, &MyGreeter{})
	log.Println("[GO] Server listen at:", addr)
	if err := s.Serve(listen); err != nil {
		log.Fatal("Error Serveing", err)
		return
	}
}

启动服务端:

客户端

package main

import (
	"context"
	"helloworld_go/pb"
	"log"
	"os"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
)

func main() {
	grpc_server_addr := os.Getenv("GRPC_SERVER")
	if grpc_server_addr == "" {
		grpc_server_addr = "127.0.0.1:9527"
	}
	conn, err := grpc.Dial(grpc_server_addr, grpc.WithTransportCredentials(insecure.NewCredentials())) // 本地测试没有 TLS, 禁用 TLS
	if err != nil {
		log.Fatal("Dial error: ", err)
	}
	defer conn.Close()

	c := pb.NewGreeterClient(conn)

	r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: "张三"})
	if err != nil {
		log.Fatal("SayHello error: ", err)
	}
	log.Println("Greeting:", r.GetMessage())
}

同样的,为了连接不同的服务端,我们的客户端通过环境变量 GRPC_SERVER 来指定服务端地址。

启动客户端:

go run client/main.go

指定环境变量来启动客户端:

GRPC_SERVER=127.0.0.1:9527 go run client/main.go