Hello gRPC
按照惯例,这里从一个Hello项目开始,本项目定义了一个Hello Service,客户端发送包含字符串名字的请求,服务端返回Hello消息。
流程:
编写.proto
描述文件
编译生成.pb.go
文件
服务端实现约定的接口并提供服务
客户端按照约定调用方法请求服务
项目目录:
1 2 3 4 5 6 7 8 9 10 11
| $GOPATH/src/grpc-go-practice/ example/ |—— hello/ |—— client/ |—— main.go |—— server/ |—— main.go |—— proto/ |—— hello.proto |—— hello.pb.go
|
示例代码
描述文件:proto/hello.proto
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| syntax = "proto3"; package proto; service Hello { rpc SayHello(HelloRequest) returns (HelloReply) {} } message HelloRequest { string name = 1; } message HelloReply { string message = 1; }
|
hello.proto文件中定义了一个Hello Service,该服务包含一个SayHello
方法,同时声明了HelloRequest
和HelloReply
消息结构用于请求和响应。客户端使用HelloRequest
参数调用SayHello
方法请求服务端,服务端响应HelloReply
消息。protobuf的语法后面会详细介绍,这里先不用过多纠结。
编译生成.pb.go
文件:
1 2
| # 编译hello.proto protoc -I .
|
生成的.pb.go
文件,按照.proto
文件中的说明,包含服务端接口HelloServer
描述,客户端接口及实现HelloClient
,及HelloRequest
、HelloResponse
结构体,不要手动编辑该文件。
实现服务端接口:server/main.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| package main import ( "net" pb "go-grpc-practice/example/proto" "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/grpclog" ) const ( Address = "127.0.0.1:50052" ) type helloService struct{} var HelloService = helloService{} func (h helloService) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) { resp := new(pb.HelloReply) resp.Message = "Hello " + in.Name + "." return resp, nil } func main() { listen, err := net.Listen("tcp", Address) if err != nil { grpclog.Fatalf("failed to listen: %v", err) } s := grpc.NewServer() pb.RegisterHelloServer(s, HelloService) grpclog.Println("Listen on " + Address) s.Serve(listen) }
|
运行:
1 2 3
| go run main.go Listen on 50051
|
服务端引入编译后的proto
包,实现约定的接口,接口描述可以查看hello.pb.go
文件中的HelloServer
接口描述。实例化grpc Server并注册HelloService,开始提供服务。
客户端调用:client/main.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| package main import ( pb "go-grpc-practice/example/proto" "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/grpclog" ) const ( 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) reqBody := new(pb.HelloRequest) reqBody.Name = "gRPC" r, err := c.SayHello(context.Background(), reqBody) if err != nil { grpclog.Fatalln(err) } grpclog.Println(r.Message) }
|
运行:
1 2 3
| go run main.go Hello gRPC
|
客户端初始化连接后直接调用声明的方法,即可向服务端发起请求,使用姿势就像调用本地方法一样。如果你收到了”Hello gRPC”的回复,恭喜你已经会使用go-gRPC了。
下节将详细介绍protobuf的语法,并详细解析protobuf声明与编译后golang代码的对应关系。
参考
本系列示例代码