grpc的四种调用方式

本文主要介绍 gRPC 的四种调用方式。

官方教程

https://grpc.io/docs/languages/go/basics/

gRPC 的四种调用方式

分为四部分:Unary RPCClient StreamingServer StreamingBidirectional Streaming

1. Unary RPC

客户端发送单个请求,服务器返回单个响应,类似http请求,此处代码略过…

2. Client Streaming

客户端发送多条消息,服务器接收所有消息后返回一个聚合响应

客户端示例:

userStream, _ := aiClient.ChatWithUserStream(ctx)
words := []string{"how", "are", "you"}
for _, word := range words {
    userStream.Send(&pb.ChatMsg{Msg: word})
}
userStreamReply, _ := userStream.CloseAndRecv()

服务端示例:

func (s *AIService) ChatWithUserStream(stream grpc.ClientStreamingServer[pb.ChatMsg, pb.ChatMsg]) error {
    respMsg := ""
    for {
        chatReq, err := stream.Recv()
        if err == io.EOF {
            return stream.SendAndClose(&pb.ChatMsg{Msg: respMsg})
        }
        respMsg = respMsg + chatReq.Msg
    }
}

3. Server Streaming

客户端发送单个请求,服务器返回多条消息流

客户端示例:

aiStream, _ := aiClient.ChatWithAIStream(ctx, &pb.ChatMsg{Msg: "hello,I want to ask a question"})
for {
    aiStreamReply, err := aiStream.Recv()
    if err == io.EOF {
        break
    }
    log.Println(aiStreamReply.Msg)
}

服务端示例:

func (s *AIService) ChatWithAIStream(in *pb.ChatMsg, stream grpc.ServerStreamingServer[pb.ChatMsg]) error {
    stream.Send(&pb.ChatMsg{Msg: in.Msg})
    words := []string{"wait", "a", "minute"}
    for _, word := range words {
        stream.Send(&pb.ChatMsg{Msg: word})
    }
    return nil
}

4. Bidirectional Streaming

客户端和服务器都可以随时发送消息,类似于实时聊天

客户端示例:

userAIStream, _ := aiClient.ChatWithUserAIStream(ctx)

// 启动 goroutine 接收服务器消息
go func() {
    for {
        userAIStreamReply, err := userAIStream.Recv()
        if err != nil {
            log.Fatalf("failed to get userAIStreamReply,err:%v", err)
        }
        log.Println(userAIStreamReply.Msg)
    }
}()

// 从标准输入读取并发送消息
for {
    reader := bufio.NewReader(os.Stdin)
    line, _ := reader.ReadString('\n')
    userAIStream.Send(&pb.ChatMsg{Msg: line})
}

服务端示例:

func (s *AIService) ChatWithUserAIStream(stream grpc.BidiStreamingServer[pb.ChatMsg, pb.ChatMsg]) error {
    for {
        chatReq, err := stream.Recv()
        if err == io.EOF {
            break
        }
        if err != nil {
            return err
        }
        replyMsg := replace(chatReq.Msg)  // 文本转换
        stream.Send(&pb.ChatMsg{Msg: replyMsg})
    }
    return nil
}

后端代码地址

https://cnb.cool/codepzj/goplayground/-/tree/main/rpc-learn/grpc-4method