gRPC 例程:Go 语言四种通信模式
目标
用 Go 实现 gRPC 的四种通信模式:Unary、Server Streaming、Client Streaming、Bidirectional Streaming。
Proto 定义
syntax = "proto3";
package calculator;
option go_package = "example.com/grpc-demo/calculator";
service Calculator {
rpc Add(AddRequest) returns (AddResponse);
rpc Fibonacci(FibRequest) returns (stream FibResponse);
rpc Average(stream AvgRequest) returns (AvgResponse);
rpc Chat(stream ChatMessage) returns (stream ChatMessage);
}
message AddRequest { int32 a = 1; int32 b = 2; }
message AddResponse { int32 result = 1; }
message FibRequest { int32 n = 1; }
message FibResponse { int64 value = 1; }
message AvgRequest { int32 num = 1; }
message AvgResponse { double average = 1; }
message ChatMessage { string user = 1; string text = 2; }
服务端实现
package main
import (
"context"
"io"
"log"
"net"
pb "example.com/grpc-demo/calculator"
"google.golang.org/grpc"
)
type server struct {
pb.UnimplementedCalculatorServer
}
func (s *server) Add(ctx context.Context, req *pb.AddRequest) (*pb.AddResponse, error) {
return &pb.AddResponse{Result: req.A + req.B}, nil
}
func (s *server) Fibonacci(req *pb.FibRequest, stream pb.Calculator_FibonacciServer) error {
var a, b int64 = 0, 1
for i := int32(0); i < req.N; i++ {
stream.Send(&pb.FibResponse{Value: a})
a, b = b, a+b
}
return nil
}
func (s *server) Average(stream pb.Calculator_AverageServer) error {
var sum, count int32
for {
req, err := stream.Recv()
if err == io.EOF {
return stream.SendAndClose(&pb.AvgResponse{
Average: float64(sum) / float64(count),
})
}
if err != nil { return err }
sum += req.Num
count++
}
}
func (s *server) Chat(stream pb.Calculator_ChatServer) error {
for {
msg, err := stream.Recv()
if err == io.EOF { return nil }
if err != nil { return err }
log.Printf("[%s]: %s", msg.User, msg.Text)
stream.Send(&pb.ChatMessage{
User: "Server",
Text: "收到: " + msg.Text,
})
}
}
func main() {
lis, _ := net.Listen("tcp", ":50051")
s := grpc.NewServer()
pb.RegisterCalculatorServer(s, &server{})
log.Println("gRPC 服务启动在 :50051")
s.Serve(lis)
}
运行步骤
protoc --go_out=. --go-grpc_out=. calculator.proto
go run server/main.go
go run client/main.go
运行结果示例
2024/01/01 gRPC 服务启动在 :50051
[Alice]: Hello!
[Bob]: Hi there!
四种模式对比
| 模式 |
客户端 |
服务端 |
典型场景 |
| Unary |
1 请求 → 1 响应 |
1 请求 → 1 响应 |
简单查询 |
| Server Stream |
1 请求 → 流式接收 |
1 请求 → 流式发送 |
日志订阅 |
| Client Stream |
流式发送 → 1 响应 |
流式接收 → 1 响应 |
文件上传 |
| Bidi Stream |
自由收发 |
自由收发 |
聊天、实时协作 |