按照惯例,这里也从一个Hello项目开始,本项目定义了一个Hello Service,客户端发送包含字符串名字的请求,服务端返回Hello消息。
流程:
.proto
.pb.go
项目结构:
|—— hello/ |—— client/ |—— main.go // 客户端 |—— server/ |—— main.go // 服务端 |—— proto/ |—— hello/ |—— hello.proto // proto描述文件 |—— hello.pb.go // proto编译后文件
Step1:编写描述文件:hello.proto
syntax = "proto3"; // 指定proto版本 package hello; // 指定默认包名 // 指定golang包名 option go_package = "hello"; // 定义Hello服务 service Hello { // 定义SayHello方法 rpc SayHello(HelloRequest) returns (HelloResponse) {} } // HelloRequest 请求结构 message HelloRequest { string name = 1; } // HelloResponse 响应结构 message HelloResponse { string message = 1; }
hello.proto文件中定义了一个Hello Service,该服务包含一个SayHello方法,同时声明了HelloRequest和HelloResponse消息结构用于请求和响应。客户端使用HelloRequest参数调用SayHello方法请求服务端,服务端响应HelloResponse消息。一个最简单的服务就定义好了。
hello.proto
SayHello
HelloRequest
HelloResponse
Step2:编译生成.pb.go文件
$ cd proto/hello # 编译hello.proto $ protoc -I . --go_out=plugins=grpc:. ./hello.proto
在当前目录内生成的hello.pb.go文件,按照.proto文件中的说明,包含服务端接口HelloServer描述,客户端接口及实现HelloClient,及HelloRequest、HelloResponse结构体。
hello.pb.go
HelloServer
HelloClient
注意:不要手动编辑该文件
Step3:实现服务端接口 server/main.go
server/main.go
package main import ( "fmt" "net" pb "github.com/jergoo/go-grpc-example/proto/hello" // 引入编译生成的包 "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/grpclog" ) const ( // Address gRPC服务地址 Address = "127.0.0.1:50052" ) // 定义helloService并实现约定的接口 type helloService struct{} // HelloService Hello服务 var HelloService = helloService{} // SayHello 实现Hello服务接口 func (h helloService) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloResponse, error) { resp := new(pb.HelloResponse) resp.Message = fmt.Sprintf("Hello %s.", in.Name) return resp, nil } func main() { listen, err := net.Listen("tcp", Address) if err != nil { grpclog.Fatalf("Failed to listen: %v", err) } // 实例化grpc Server s := grpc.NewServer() // 注册HelloService pb.RegisterHelloServer(s, HelloService) grpclog.Println("Listen on " + Address) s.Serve(listen) }
服务端引入编译后的proto包,定义一个空结构用于实现约定的接口,接口描述可以查看hello.pb.go文件中的HelloServer接口描述。实例化grpc Server并注册HelloService,开始提供服务。
proto
运行:
$ go run main.go Listen on 127.0.0.1:50052 //服务端已开启并监听50052端口
Step4:实现客户端调用 client/main.go
client/main.go
package main import ( pb "github.com/jergoo/go-grpc-example/proto/hello" // 引入proto包 "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/grpclog" ) const ( // Address gRPC服务地址 Address = "127.0.0.1:50052" ) func main() { // 连接 conn, err := grpc.Dial(Address, grpc.WithInsecure()) if err != nil { grpclog.Fatalln(err) } defer conn.Close() // 初始化客户端 c := pb.NewHelloClient(conn) // 调用方法 req := &pb.HelloRequest{Name: "gRPC"} res, err := c.SayHello(context.Background(), req) if err != nil { grpclog.Fatalln(err) } grpclog.Println(res.Message) }
客户端初始化连接后直接调用hello.pb.go中实现的SayHello方法,即可向服务端发起请求,使用姿势就像调用本地方法一样。
$ go run main.go Hello gRPC. // 接收到服务端响应
如果你收到了"Hello gRPC"的回复,恭喜你已经会使用github.com/jergoo/go-grpc-example/proto/hello了。
建议到这里仔细看一看hello.pb.go文件中的内容,对比hello.proto文件,理解protobuf中的定义转换为golang后的结构。
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8