Grpc 介绍
1. 什么是 grpc
gRPC 是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计。目前提供 C、Java 和 Go 语言版本,分别是 grpc, grpc-java, grpc-go。gRPC 基于 HTTP/2 标准设计,带来诸如双向流、流控、头部压缩、单 TCP 连接上的多复用请求等特。这些特性使得其在移动设备上表现更好,更省电和节省空间占用。
2. grpc 的优势
- 简单易用,基于 ProtoBuf 定义接口,自动生成代码,使用起来非常方便。
- 支持多种语言,目前支持 C、Java、Go,分别是 grpc, grpc-java, grpc-go。
- 基于 HTTP/2 标准设计,带来诸如双向流、流控、头部压缩、单 TCP 连接上的多复用请求等特性。
3. grpc 的缺点
- 由于是基于 HTTP/2 标准设计,所以只能在 HTTP/2 上使用,不能在 HTTP/1.1 上使用。
- 由于是基于 ProtoBuf 定义接口,所以只能使用 ProtoBuf 序列化,不能使用 JSON 等其他序列化方式。
4. grpc 的应用场景
- 服务间通信,比如微服务之间的通信。
- 客户端与服务端通信,比如移动端与服务端通信。
5. grpc 的使用
5.1 安装
5.2 定义接口
syntax = "proto3";
package helloworld;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
5.3 生成代码
protoc -I helloworld/ helloworld/helloworld.proto --go_out=plugins=grpc:helloworld
5.4 实现接口
package main
import (
"context"
"log"
"net"
pb "github.com/zhengyscn/golang-doc/grpc/helloworld"
"google.golang.org/grpc"
)
const (
port = ":50051"
)
// 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
}
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)
}
}
5.5 启动服务
go run server/main.go
5.6 调用接口
package main
import (
"context"
"log"
"os"
"time"
pb "github.com/zhengyscn/golang-doc/grpc/helloworld"
"google.golang.org/grpc"
)
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.Message)
}
5.7 运行客户端
go run client/main.go