03.gRPC示例
本文通过一个示例介绍gRPC服务开发过程,示例创建两个项目,一个服务端,一个客户端。
完整代码参见 grpc-testing v0.0.1
初始化结构
$ mkdir -p grpc-testing-{server,client}/api
$ touch grpc-testing-{server,client}/{main.go,generate.go} grpc-testing-server/api/echo.proto
$ cd grpc-testing-server
$ go mod init app/grpc-testing-server
$ cd ../grpc-testing-client
$ go mod init app/grpc-testing-client
两个项目共同的部分
*/generate.go
//go:generate sh -c "protoc --go_out=. --go-grpc_out=. api/*.proto"
package main
*/api/echo.proto
syntax="proto3";
package echo;
option go_package="api/echo";
message EchoRequest {
string msg = 1;
}
message EchoResponse {
string msg = 1;
}
service echo {
rpc Echo(EchoRequest) returns (EchoResponse) {}
}
这里定义了两个 message 和一个 RPC 服务
生成 gRPC 代码
$ cd grpc-testing-server
$ go generate ./...
$ cd ../grpc-testing-client
$go generate ./...
服务端
代码
grpc-testing-server/main.go
package main
import (
"app/grpc-testing-server/api/echo"
"context"
"log"
"net"
"google.golang.org/grpc"
)
type EchoServer struct {
echo.UnimplementedEchoServer
}
func (e *EchoServer) Echo(ctx context.Context, par *echo.EchoRequest) (*echo.EchoResponse, error) {
result := &echo.EchoResponse{
Msg: par.GetMsg(),
}
return result, nil
}
func main() {
log.Println("Go")
listen, err := net.Listen("tcp", ":8080")
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
echo.RegisterEchoServer(s, &EchoServer{})
if err := s.Serve(listen); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
EchoServer
实现了protoc
生成的EchoServer
接口 ( 接口定义在echo_grpc.pb.go
中) 。主要的业务方法Echo
实现了具体业务
echo.RegisterEchoServer(s, &EchoServer{})
将实现类注册到 grpc Server
编译服务端
$ cd grpc-testing-server
$ go mod tidy
$ go build
客户端
代码
grpc-testing-client/main.go
package main
import (
"app/grpc-testing-client/api/echo"
"context"
"log"
"google.golang.org/grpc"
)
func main() {
conn, err := grpc.Dial("127.0.0.1:8080", grpc.WithInsecure(), grpc.WithBlock())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := echo.NewEchoClient(conn)
ctx, cancle := context.WithCancel(context.Background())
defer cancle()
r, err := c.Echo(ctx, &echo.EchoRequest{Msg: "hello"})
if err != nil {
log.Fatalf("echo failed :%#v", err)
}
log.Print(r.GetMsg())
}
编译客户端
$ cd grpc-testing-client
$ go mod tidy
$ go build
测试
开启两个终端
终端一
$ cd grpc-testing-server
$ ./grpc-testing-server
终端二
$ cd grpc-testing-client
$ ./grpc-testing-client
总结
使用Go语言实现 gRPC 服务的过程如下:
服务端
- 安装环境
- 编写 proto 文件
- 生成 Go 文件
- 实现业务方法
- 创建gRPC server (
grpc.NewServer()
) - 调用生成的注册方法(
RegisterXXXXXX
)注册实现 - 调用
Serve
方法启动服务
客户端
- 创建连接
grpc.Dial
- 创建 Client
- 调用实际的 gRPC 方法