在这个例子中,我们将在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