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 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
}
}
启动服务端:
go run server/main.go
客户端
打开 client/go
来编写客户端代码:
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())
}
go run client/main.go
指定环境变量来启动客户端:
GRPC_SERVER=127.0.0.1:9527 go run client/main.go