Golang中四种gRPC模式举例详解

admin 轻心小站 关注 LV.19 运营
发表于Go语言交流版块 教程

gRPC 是一种高性能、开源和通用的 RPC 框架,由 Google 开发。它允许你定义服务接口,并自动生成服务端和客户端代码,以实现不同语言之间的通信。在 Go 语言中,gRPC 支持四种主要的模式

gRPC 是一种高性能、开源和通用的 RPC 框架,由 Google 开发。它允许你定义服务接口,并自动生成服务端和客户端代码,以实现不同语言之间的通信。在 Go 语言中,gRPC 支持四种主要的模式:单向流(Unary)、服务器流(Server Streaming)、客户端流(Client Streaming)和双向流(Bidirectional Streaming)。以下是这四种模式的举例详解:

1. 单向流(Unary)

单向流是最简单的 gRPC 模式,客户端发送一个请求到服务器,服务器返回一个响应。这种模式类似于常规的同步函数调用。

服务定义(proto 文件):

syntax = "proto3";

service HelloService {
  rpc SayHello (HelloRequest) returns (HelloResponse);
}

message HelloRequest {
  string name = 1;
}

message HelloResponse {
  string message = 1;
}

服务端实现(Go):

package server

import (
    "log"
    "net"

    "google.golang.org/grpc"
    pb "path/to/your/protobuf/package"
)

type helloServer struct{}

func (s *helloServer) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloResponse, error) {
    log.Printf("Received: %v", in.GetName())
    return &pb.HelloResponse{Message: "Hello " + in.GetName()}, nil
}

func main() {
    lis, err := net.Listen("tcp", ":50051")
    if err != nil {
        log.Fatalf("Failed to listen: %v", err)
    }
    s := grpc.NewServer()
    pb.RegisterHelloServiceServer(s, &helloServer{})
    log.Printf("Server listening on port %d", 50051)
    if err := s.Serve(lis); err != nil {
        log.Fatalf("Failed to serve: %v", err)
    }
}

客户端调用(Go):

package main

import (
    "context"
    "log"
    "google.golang.org/grpc"
    pb "path/to/your/protobuf/package"
)

func main() {
    conn, err := grpc.Dial(":50051", grpc.WithInsecure())
    if err != nil {
        log.Fatalf("did not connect: %v", err)
    }
    defer conn.Close()
    c := pb.NewHelloServiceClient(conn)
    name := "Kimi"
    r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: name})
    if err != nil {
        log.Fatalf("could not greet: %v", err)
    }
    log.Printf("Greeting: %s", r.Message)
}

2. 服务器流(Server Streaming)

服务器流模式允许客户端发送一个请求到服务器,服务器可以返回一个响应流。

服务定义(proto 文件):

service HelloService {
  rpc SayHelloStream (HelloRequest) returns (stream HelloResponse);
}

服务端实现(Go):

func (s *helloServer) SayHelloStream(req *pb.HelloRequest, stream pb.HelloService_SayHelloStreamServer) error {
    for i := 0; i < 5; i++ {
        if err := stream.Send(&pb.HelloResponse{Message: "Hello " + req.GetName()}); err != nil {
            return err
        }
    }
    return nil
}

客户端调用(Go):

r, err := c.SayHelloStream(context.Background(), &pb.HelloRequest{Name: "Kimi"})
if err != nil {
    log.Fatalf("could not greet: %v", err)
}
for {
    res, err := r.Recv()
    if err != nil {
        log.Fatalf("failed to receive: %v", err)
    }
    log.Printf("Greeting: %s", res.Message)
    if err == io.EOF {
        break
    }
}

3. 客户端流(Client Streaming)

客户端流模式允许客户端发送一个请求流到服务器,服务器返回一个响应。

服务定义(proto 文件):

service HelloService {
  rpc SayHelloStream (stream HelloRequest) returns (HelloResponse);
}

服务端实现(Go):

func (s *helloServer) SayHelloStream(stream pb.HelloService_SayHelloStreamServer) error {
    for {
        req, err := stream.Recv()
        if err == io.EOF {
            if err := stream.SendAndClose(&pb.HelloResponse{Message: "Hello to everyone"}); err != nil {
                return err
            }
            return nil
        }
        if err != nil {
            return err
        }
        if err := stream.Send(&pb.HelloResponse{Message: "Hello " + req.GetName()}); err != nil {
            return err
        }
    }
}

客户端调用(Go):

stream, err := c.SayHelloStream(context.Background())
if err != nil {
    log.Fatalf("could not create stream: %v", err)
}
for _, name := range []string{"Kimi", "John", "Anna"} {
    if err := stream.Send(&pb.HelloRequest{Name: name}); err != nil {
        log.Fatalf("could not send: %v", err)
    }
}
reply, err := stream.CloseAndRecv()
if err != nil {
    log.Fatalf("could not close stream: %v", err)
}
log.Printf("Greeting: %s", reply.Message)

4. 双向流(Bidirectional Streaming)

双向流模式允许客户端和服务器之间同时进行流式通信。

服务定义(proto 文件):

service HelloService {
  rpc SayHelloStream (stream HelloRequest) returns (stream HelloResponse);
}

服务端实现(Go):

func (s *helloServer) SayHelloStream(stream pb.HelloService_SayHelloStreamServer) error {
    for {
        req, err := stream.Recv()
        if err == io.EOF {
            if err := stream.SendAndClose(&pb.HelloResponse{Message: "Hello to everyone"}); err != nil {
                return err
            }
            return nil
        }
        if err != nil {
            return err
        }
        if err := stream.Send(&pb.HelloResponse{Message: "Hello " + req.GetName()}); err != nil {
            return err
        }
    }
}

客户端调用(Go):

stream, err := c.SayHelloStream(context.Background())
if err != nil {
    log.Fatalf("could not create stream: %v", err)
}
go func() {
    for _, name := range []string{"Kimi", "John", "Anna"} {
        if err := stream.Send(&pb.HelloRequest{Name: name}); err != nil {
            log.Printf("could not send: %v", err)
            return
        }
    }
}()
for {
    res, err := stream.Recv()
    if err == io.EOF {
        if err := stream.CloseSend(); err != nil {
            log.Printf("could not close stream: %v", err)
        }
        break
    }
    if err != nil {
        log.Fatalf("failed to receive: %v", err)
    }
    log.Printf("Greeting: %s", res.Message)
}

在双向流模式中,客户端和服务器可以交替发送和接收消息,直到任一方关闭连接。这种模式适用于需要全双工通信的场景,例如聊天应用或实时游戏。

以上就是 gRPC 在 Go 语言中的四种模式的详细例子。通过这些例子,你可以看到如何定义服务接口,以及如何在服务端和客户端实现这些服务。gRPC 提供了强大的跨语言服务能力,使得微服务架构中的服务间通信变得更加高效和可靠。

文章说明:

本文原创发布于探乎站长论坛,未经许可,禁止转载。

题图来自Unsplash,基于CC0协议

该文观点仅代表作者本人,探乎站长论坛平台仅提供信息存储空间服务。

评论列表 评论
发布评论

评论: Golang中四种gRPC模式举例详解

粉丝

0

关注

0

收藏

0

已有0次打赏