引言
gRPC应用程序共有四种基础的通信模式,分别为:一元RPC,服务端流RPC,客户端流RPC以及双向流RPC
注:阅读本文,如果没有gRPC基础的同学可以看我之前关于如何简单构建gRPC客户端和服务端的文章:
一元RPC模式
服务定义:
//ecommerce/order_management.pb.go
syntax="proto3";
//导入这个包,使用常用的数据类型,如StringValue
import "google/protobuf/wrappers.proto";
package ecommerce;
option go_package = "../ecommerce";
service OrderManagement{
rpc getOrder(google.protobuf.StringValue) returns (Order);//检索订单的远程方法
}
message Order{
string id = 1;
repeated string items = 2;//repeated表示该字段可以在消息中重复出现任意次
string description = 3;
float price = 4;
string destination = 5;
}
服务端实现
//main.go
package main
import (
"context"
wrapper "github.com/golang/protobuf/ptypes/wrappers"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"log"
"net"
pb "orderServiceUnaryGRPC/service/ecommerce"
)
// 服务定义
type server struct {
orderMap map[string]*pb.Order
}
const (
port = ":50051"
)
var orderMap = make(map[string]pb.Order)
// 初始化订单信息
func initSampleData() {
orderMap["102"] = pb.Order{
Id: "102", Items: []string{
"Google Pixel 3A", "Mac Book Pro"}, Destination: "Mountain View, CA", Price: 1800.00}
orderMap["103"] = pb.Order{
Id: "103", Items: []string{
"Apple Watch S4"}, Destination: "San Jose, CA", Price: 400.00}
orderMap["104"] = pb.Order{
Id: "104", Items: []string{
"Google Home Mini", "Google Nest Hub"}, Destination: "Mountain View, CA", Price: 400.00}
orderMap["105"] = pb.Order{
Id: "105", Items: []string{
"Amazon Echo"}, Destination: "San Jose, CA", Price: 30.00}
orderMap["106"] = pb.Order{
Id: "106", Items: []string{
"Amazon Echo", "Apple iPhone XS"}, Destination: "Mountain View, CA", Price: 300.00}
}
// GetOrder 通过订单编号获取订单消息
func (s *server) GetOrder(ctx context.Context, orderId *wrapper.StringValue) (*pb.Order, error) {
//服务实现
ord, exists := orderMap[orderId.Value]
if exists {
return &ord, status.New(codes.OK, "").Err()
}
return nil, status.Errorf(codes.NotFound, "Order does not exist.:", orderId)
}
func main() {
initSampleData()
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen:%v", err)
}
log.Printf("Starting gRPC listener on port:%s", port)
s := grpc.NewServer()
pb.RegisterOrderManagementServer(s, &server{
})
// 在指定端口上开始监听传入的消息
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve:%v", err)
}
}
客户端实现
//main.go
package main
import (
"context"
wrapper "github.com/golang/protobuf/ptypes/wrappers"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"log"
pb "orderServiceUnaryGRPC/client/ecommerce"
"time"
)
const (
address = "localhost:50051"
)
func main() {
conn, err := grpc.Dial(address, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatalf("Did not connect:%v", err)
}
defer conn.Close()
client := pb.NewOrderManagementClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
// 获取订单
ord, err := client.GetOrder(ctx, &wrapper.StringValue{
Value: "105"})
log.Printf("GetOrder Response ->:%v", ord)
}
服务器端流RPC模式
在一元 RPC 模式中,gRPC 服务器端和 gRPC 客户端在通信时始终只有 一个请求和一个响应。在服务器端流 RPC 模式中,服务器端在接收到 客户端的请求消息后,会发回一个响应的序列。这种多个响应所组成的 序列也被称为“流”。在将所有的服务器端响应发送完毕之后,服务器端 会以 trailer 元数据的形式将其状态发送给客户端,从而标记流的结束。
服务定义