简介
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 是什么?
在 gRPC 里客户端应用可以像调用本地对象一样直接调用另一台不同的机器上服务端应用的方法,使得您能够更容易地创建分布式应用和服务。与许多 RPC 系统类似,gRPC 也是基于以下理念:定义一个服务,指定其能够被远程调用的方法(包含参数和返回类型)。在服务端实现这个接口,并运行一个 gRPC 服务器来处理客户端调用。在客户端拥有一个存根能够像服务端一样的方法。
gRPC 客户端和服务端可以在多种环境中运行和交互 ,并且可以用任何 gRPC 支持的语言来编写。所以,你可以很容易地用 Java 创建一个 gRPC 服务端,用 Go、Python、Ruby 来创建客户端。此外,Google 最新 API 将有 gRPC 版本的接口,使你很容易地将 Google 的功能集成到你的应用里。
使用 protocol buffers
gRPC 默认使用 protocol buffers,这是 Google 开源的一套成熟的结构数据序列化机制(当然也可以使用其他数据格式如 JSON)。正如你将在下方例子里所看到的,你用 proto files 创建 gRPC 服务,用 protocol buffers 消息类型来定义方法参数和返回类型。你可以在 Protocol Buffers 文档找到更多关于 Protocol Buffers 的资料。
Protocol buffers 版本
尽管 protocol buffers 对于开源用户来说已经存在了一段时间,例子内使用的却一种名叫 proto3 的新风格的 protocol buffers,它拥有轻量简化的语法、一些有用的新功能,并且支持更多新语言。 我们通常建议你在 gRPC 里使用 proto3,因为这样你可以使用 gRPC 支持全部范围的的语言,并且能避免 proto2 客户端与 proto3 服务端交互时出现的兼容性问题,反之亦然。
protoc compiler安装
下载proto windows版本并安装
官方地址:https://github.com/protocolbuffers/protobuf/releases
解压后复制bin目录下的protoc.exe
到 环境变量能访问到的目录中,比如我就放到go的安装目录了 /c/go/go1.18/bin/go
Go plugins for the protocol compiler 安装
如果使用go get -u github.com/golang/protobuf/protoc-gen-go
可能会出现如下错误:
go: module github.com/golang/protobuf is deprecated: Use the "google.golang.org/protobuf" module instead.go get: installing executables with
'go get' in module mode is deprecated. Use 'go install pkg@version' instead.For more information,
see https://golang.org/doc/go-get-install-deprecation or run 'go help get' or 'go help install'.
使用下面的命令进行下载
$ go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28 $ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2
安装成功后,在GOPATH\bib
目录中可以看到proroc-gen-go.exe
两个全部安装成功后,查看下版本号
$ protoc --version libprotoc 22.2 $ protoc-gen-go.exe --version protoc-gen-go.exe v1.30.0
大家如果觉得上面单独安装问题很多,也可以直接参考这篇文章,使用一键安装和版本控制
PowerProto: gRPC工具链(protoc, protoc-gen-go)的一键安装与版本控制 : https://117.119.65.11:10064/?id=4078
先介绍一下我们最后的目录结构
example hello hello hello.proto hello.pb.go hello_grpc.pb.go client client.go server server.go
定义服务
syntax = "proto3"; // 版本信息,不指定会报错 option java_package = "io.grpc.examples"; package hello; //生成go文件的包名 option go_package ="./hello"; // 表示在当前文件夹下的pb包中 // The greeter service definition. service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) {} rpc SayHelloAgain (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; }
生成 gRPC 代码
为了生成客户端和服务端接口,运行 protocol buffer 编译器:
protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative hello/hello.proto
这生成了 hello.pb.go 和 hello_grpc.pb.go ,包含了我们生成的客户端和服务端类,此外还有用于填充、序列化、提取 HelloRequest
和 HelloResponse
消息类型的类。
写一个服务器
需要提供一个 gRPC 服务的另一个主要功能是让这个服务实在在网络上可用。
hello/server/server.go
package main import ( "context" "flag" "fmt" "gogin/proto/hello/hello" "google.golang.org/grpc" "log" "net" ) var ( port = flag.Int("port", 50051, "The server port") ) // server is used to implement helloworld.GreeterServer. type server struct { hello.UnimplementedGreeterServer } // SayHello implements helloworld.GreeterServer func (s *server) SayHello(ctx context.Context, in *hello.HelloRequest) (*hello.HelloReply, error) { log.Printf("Received: %v", in.GetName()) return &hello.HelloReply{Message: "Hello " + in.GetName()}, nil } func main() { flag.Parse() lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port)) if err != nil { log.Fatalf("failed to listen: %v", err) } s := grpc.NewServer() hello.RegisterGreeterServer(s, &server{}) log.Printf("server listening at %v", lis.Addr()) if err := s.Serve(lis); err != nil { log.Fatalf("failed to serve: %v", err) } }
写一个客户端
package main import ( "context" "flag" "gogin/proto/hello/hello" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "log" "time" ) const ( defaultName = "world" ) var ( addr = flag.String("addr", "localhost:50051", "the address to connect to") name = flag.String("name", defaultName, "Name to greet") ) func main() { flag.Parse() // Set up a connection to the server. conn, err := grpc.Dial(*addr, grpc.WithTransportCredentials(insecure.NewCredentials())) if err != nil { log.Fatalf("did not connect: %v", err) } defer conn.Close() c := hello.NewGreeterClient(conn) // Contact the server and print out its response. ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() r, err := c.SayHello(ctx, &hello.HelloRequest{Name: *name}) if err != nil { log.Fatalf("could not greet: %v", err) } log.Printf("Greeting: %s", r.GetMessage()) }
调用 RPC
我们创建并填充一个
HelloRequest
发送给服务。我们用请求调用存根的
SayHello()
,如果 RPC 成功,会得到一个填充的HelloReply
,从其中我们可以获得 greeting。
运行服务端,进入hello/server目录:
go run server.go 2023/04/03 14:35:19 server listening at [::]:50051 2023/04/03 14:35:19 Received: world
运行客户端,进入hello/client目录:
go run client.go 2023/04/03 14:35:19 Greeting: Hello world
参考
grpc快速开始: https://grpc.io/docs/languages/go/quickstart/
- 本文固定链接: https://117.119.65.11:10064/?id=3209
- 转载请注明: admin 于 PHP面试网 发表
《本文》有 0 条评论