Bu örnekte, Golang gRPC uygulamasında bir istemci taraflı akış örneği oluşturacağız. Bu bire birçok ilişki gibidir. İstemci birçok istek gönderir ve sunucu bir tane ile yanıt verir. İstemci, geriye hiçbir şey kalmayana kadar yayın yapar. Mesajlar sunucu tarafından okunduktan sonra, her ikisi de çıkar. Daha fazla bilgi için dokümantasyonu okuyun.


Proto dosyası


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;
}


Derlenmiş dosyayı oluşturmak için protoc --go_out=plugins=grpc:. --go_opt=paths=source_relative pkg/protobuf/port/*.proto komutunu çalıştırın.


Client


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
}

Server


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)
}
}

Test


Önce sunucunuzu, sonra istemciyi çalıştırın. Sonuç aşağıdaki gibi olmalıdır.


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