gRPC 是一种高性能、开源和通用的 RPC 框架,由 Google 开发。它允许你定义服务接口,并自动生成服务端和客户端代码,以实现不同语言之间的通信。在 Go 语言中,gRPC 支持四种主要的模式
gRPC 是一种高性能、开源和通用的 RPC 框架,由 Google 开发。它允许你定义服务接口,并自动生成服务端和客户端代码,以实现不同语言之间的通信。在 Go 语言中,gRPC 支持四种主要的模式:单向流(Unary)、服务器流(Server Streaming)、客户端流(Client Streaming)和双向流(Bidirectional Streaming)。以下是这四种模式的举例详解:
单向流是最简单的 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)
}
服务器流模式允许客户端发送一个请求到服务器,服务器可以返回一个响应流。
服务定义(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
}
}
客户端流模式允许客户端发送一个请求流到服务器,服务器返回一个响应。
服务定义(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)
双向流模式允许客户端和服务器之间同时进行流式通信。
服务定义(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 提供了强大的跨语言服务能力,使得微服务架构中的服务间通信变得更加高效和可靠。
暂无管理员
粉丝
0
关注
0
收藏
0