用Golang创建一个客户端的gRPC流的指南

194 阅读1分钟

在这个例子中,我们将在Golang gRPC应用程序中创建一个客户端流媒体实例。这就像一对多的关系。客户端发送许多请求,服务器以一来回应。客户端进行流式传输,直到没有剩余的内容。一旦所有的请求被服务器读取,他们都会退出。更多信息请阅读文档

Proto文件

syntax = "proto3";
 
package port;
 
option go_package = "github.com/you/pirate/pkg/protobuf/port;protoport";

service PortService {
    rpc Create(stream CreateRequest) returns (CreateResponse) {}
}

message CreateRequest {
    string id = 1;
    string name = 2;
}

message CreateResponse {
    int32 total = 1;
}

运行protoc --go_out=plugins=grpc:. --go_opt=paths=source_relative pkg/protobuf/port/*.proto 命令来生成编译文件。

客户端

main.go

package main

import (
	"context"
	"log"

	"github.com/you/pirate/internal/pkg/transport/client/grpc"

	gogrpc "google.golang.org/grpc"
)

func main() {
	log.Println("client")

	conn, err := gogrpc.Dial(":50051", gogrpc.WithInsecure(), gogrpc.WithBlock())
	if err != nil {
		log.Fatalln(err)
	}
	defer conn.Close()

	portClient := grpc.NewPort(conn)
	if err := portClient.Create(context.Background()); err != nil {
		log.Fatalln(err)
	}
}

grpc.go

package grpc

import (
	"context"
	"fmt"
	"log"

	"google.golang.org/grpc"

	protoport "github.com/you/pirate/pkg/protobuf/port"
)

type Port struct {
	client protoport.PortServiceClient
}

func NewPort(conn grpc.ClientConnInterface) Port {
	return Port{
		client: protoport.NewPortServiceClient(conn),
	}
}

func (p Port) Create(ctx context.Context) error {
	ctx, cancel := context.WithCancel(ctx)
	defer cancel()

	// I am hardcoding this here but you should not!
	requests := []*protoport.CreateRequest{
		{Id: "id-1", Name: "name-1"},
		{Id: "id-2", Name: "name-2"},
		{Id: "id-3", Name: "name-3"},
		{Id: "id-4", Name: "name-4"},
	}

	stream, err := p.client.Create(ctx)
	if err != nil {
		return fmt.Errorf("create stream: %w", err)
	}

	for _, request := range requests {
		if err := stream.Send(request); err != nil {
			return fmt.Errorf("send stream: %w", err)
		}
	}

	response, err := stream.CloseAndRecv()
	if err != nil {
		return fmt.Errorf("close and receive: %w", err)
	}

	log.Printf("%+v\n", response)

	return nil
}

服务器

main.go

package main

import (
	"log"
	"net"

	"github.com/you/pirate/internal/pkg/transport/server/grpc"

	gogrpc "google.golang.org/grpc"

	protoport "github.com/you/pirate/pkg/protobuf/port"
)

func main() {
	log.Println("server")

	listener, err := net.Listen("tcp", ":50051")
	if err != nil {
		log.Fatalln(err)
	}
 
	server := gogrpc.NewServer()
	protoServer := grpc.Port{}
 
	protoport.RegisterPortServiceServer(server, protoServer)
 
	log.Fatalln(server.Serve(listener))
}

grpc.go

package grpc

import (
	"io"
	"log"

	protoport "github.com/you/pirate/pkg/protobuf/port"
)

type Port struct{}

func (p Port) Create(stream protoport.PortService_CreateServer) error {
	var total int32

	for {
		port, err := stream.Recv()
		if err == io.EOF {
			return stream.SendAndClose(&protoport.CreateResponse{
				Total: total,
			})
		}
		if err != nil {
			return err
		}

		total++
		log.Printf("%+v\n", port)
	}
}

测试

先运行你的服务器,然后再运行客户端。结果应该是这样的:

server$ go run main.go
2021/04/13 16:27:26 server
2021/04/13 16:27:31 id:"id-1" name:"name-1"
2021/04/13 16:27:31 id:"id-2" name:"name-2"
2021/04/13 16:27:31 id:"id-3" name:"name-3"
2021/04/13 16:27:31 id:"id-4" name:"name-4"


client$ go run main.go
2021/04/13 16:27:31 client
2021/04/13 16:27:31 total:4