gRPC应用golang
Posted embedded-linux
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了gRPC应用golang相关的知识,希望对你有一定的参考价值。
1. gRPC简述
gRPC 是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计。目前提供 C、Java 和 Go 语言版本,分别是:grpc, grpc-java, grpc-go. 其中 C 版本支持 C, C++, Node.js, Python, Ruby, Objective-C, php 和 C# 支持.
gRPC 基于 HTTP/2 标准设计,带来诸如双向流、流控、头部压缩、单 TCP 连接上的多复用请求等特。这些特性使得其在移动设备上表现更好,更省电和节省空间占用。
gRPC默认使用protocol buffers作为交换数据序列化的机制,即gRPC底层依赖protobuf。
2. gRPC-go安装
1)安装protobuf编译器protoc,可直接从https://github.com/protocolbuffers/protobuf/releases安装稳定版本。
2)安装golang插件protoc-gen-go。
$ go get -u github.com/golang/protobuf/protoc-gen-go
3)下载grpc-go仓库
grpc-go仓库原地址为:google.golang.org/grpc,由于原地址屏蔽,需要从github拉下来后拷贝到$GOPATH/src/google.golang.org/grpc。
git clone https://github.com/grpc/grpc-go.git $GOPATH/src/google.golang.org/grpc
4)配置goproxy,在/etc/profile最后加上如下代码后source。
export GO111MODULE=on export GOPROXY="https://goproxy.cn"
5)直接编译例程
$ go get google.golang.org/grpc/examples/helloworld/greeter_client
$ go get google.golang.org/grpc/examples/helloworld/greeter_server
编译成功后可执行文件位于$GOPATH/bin下。
3. gRPC-go应用
1 定义服务
一个 RPC 服务通过参数和返回类型来指定可以远程调用的方法。gRPC通过protobuf来实现。
使用 protocol buffers 接口定义语言来定义服务方法,用 protocol buffer 来定义参数和返回类型。客户端和服务端均使用服务定义生成的接口代码。
syntax = "proto3"; option java_package = "io.grpc.examples"; package helloworld; // The greeter service definition. service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) {} } // The request message containing the user‘s name. message HelloRequest { string name = 1; } // The response message containing the greetings message HelloReply { string message = 1; }
2. 生成gRPC代码
使用protoc来生成创建应用所需的特定客户端和服务端的代码,文件*.pb.go。生成的代码同时包括客户端的存根和服务端要实现的抽象接口,均包含Greeter所定义的方法。
进入helloworld.proto所在目录:
protoc -I . helloworld.proto --go_out=plugins=grpc:.
注意:生成兼容gRPC代码。
若protoc文件指定了RPC services,protoc-gen-go可以生成兼容gRPC的代码,需要指定go_out的plugins参数,常用方法如下:
If a proto file specifies RPC services, protoc-gen-go can be instructed to generate code compatible with gRPC (http://www.grpc.io/). To do this, pass the plugins
parameter to protoc-gen-go; the usual way is to insert it into the --go_out argument to protoc:
protoc --go_out=plugins=grpc:. *.proto
若不指定plugins=grpc参数,则生成的*.pb.go仅包含protobuf相关的代码,不包含grpc相关代码。
注意:插件参数列表
插件参数列表用逗号(,)分割,插件参数与输出路径用冒号(:)分隔。
To pass extra parameters to the plugin, use a comma-separated parameter list separated from the output directory by a colon:
protoc --go_out=plugins=grpc,import_path=mypackage:. *.proto
- paths=(import | source_relative) - specifies how the paths of generated files are structured. See the "Packages and imports paths" section above. The default is import.
- plugins=plugin1+plugin2 - specifies the list of sub-plugins to load. The only plugin in this repo is grpc.
- Mfoo/bar.proto=quux/shme - declares that foo/bar.proto is associated with Go package quux/shme. This is subject to the import_prefix parameter.
The following parameters are deprecated and should not be used:
- import_prefix=xxx - a prefix that is added onto the beginning of all imports.
- import_path=foo/bar - used as the package if no input files declare go_package. If it contains slashes, everything up to the rightmost slash is ignored.
3. server端
服务器有一个server结构,通过实现SayHello()方法,实现了从proto服务定义生成的GreeterServer接口。
// server is used to implement helloworld.GreeterServer. type server struct{} // SayHello implements helloworld.GreeterServer func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) { return &pb.HelloReply{Message: "Hello " + in.Name}, nil }
需要提供一个gRPC服务的另一个主要功能是让这个服务在网络上可用。
const ( port = ":50051" ) ... func main() { lis, err := net.Listen("tcp", port) if err != nil { log.Fatalf("failed to listen: %v", err) } s := grpc.NewServer() pb.RegisterGreeterServer(s, &server{}) s.Serve(lis) }
详细代码如下:
package main import ( "context" "log" "net" "google.golang.org/grpc" pb "google.golang.org/grpc/examples/helloworld/helloworld" ) const ( port = ":50051" ) // server is used to implement helloworld.GreeterServer. type server struct { pb.UnimplementedGreeterServer } // SayHello implements helloworld.GreeterServer func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) { log.Printf("Received: %v", in.GetName()) return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil } func main() { lis, err := net.Listen("tcp", port) if err != nil { log.Fatalf("failed to listen: %v", err) } s := grpc.NewServer() pb.RegisterGreeterServer(s, &server{}) if err := s.Serve(lis); err != nil { log.Fatalf("failed to serve: %v", err) } }
4. client端
// Package main implements a client for Greeter service. package main import ( "context" "log" "os" "time" "google.golang.org/grpc" pb "google.golang.org/grpc/examples/helloworld/helloworld" ) const ( address = "localhost:50051" defaultName = "world" ) func main() { // Set up a connection to the server. conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock()) if err != nil { log.Fatalf("did not connect: %v", err) } defer conn.Close() c := pb.NewGreeterClient(conn) // Contact the server and print out its response. name := defaultName if len(os.Args) > 1 { name = os.Args[1] } ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name}) if err != nil { log.Fatalf("could not greet: %v", err) } log.Printf("Greeting: %s", r.GetMessage()) }
参考:
1. gRPC 官方文档中文版 http://doc.oschina.net/grpc?t=56831
2. gRPC in 3 minutes (Go) https://github.com/grpc/grpc-go/tree/master/examples
3. https://github.com/golang/protobuf
4. gRPC应用C++
以上是关于gRPC应用golang的主要内容,如果未能解决你的问题,请参考以下文章