This is the 16th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

We continue with the implementation of the remaining two approaches – client-side streaming RPC and bidirectional streaming RPC.

Clientside Streaming RPC:

The client sends multiple RPC requests to the server through streaming RPC, and the server sends a response to the client

Proto :

syntax = "proto3";

package proto;

message String {
    string value = 1;
}

service HelloService {
    rpc Hello (stream String) returns (String){};
}
Copy the code

server:

package main

import (
	"google.golang.org/grpc"
	"io"
	"log"
	"net"
	pb "rpc/proto" // Set the reference alias
)

// HelloServiceImpl defines our service
type HelloServiceImpl struct{}

// Implement the Hello method
func (p *HelloServiceImpl) Hello(stream pb.HelloService_HelloServer) error {
	for {
		resp, err := stream.Recv()
		if err == io.EOF {
			return stream.SendAndClose(&pb.String{Value:"say.hello"})}iferr ! =nil {
			return err
		}

		log.Printf("resp: %v", resp)
	}

	return nil
}

func main(a) {
	// Create a gRPC server instance
	grpcServer := grpc.NewServer()
	// Register our service on the gRPC server
	pb.RegisterHelloServiceServer(grpcServer, new(HelloServiceImpl))

	lis, err := net.Listen("tcp".": 1234")
	iferr ! =nil {
		log.Fatal(err)
	}
	log.Println(" net.Listing...")
	// Use the server Serve() method and our port information area to block and wait until the process is killed or Stop() is called
	err = grpcServer.Serve(lis)
	iferr ! =nil {
		log.Fatalf("grpcServer.Serve err: %v", err)
	}
}
Copy the code

As shown above, we processed each Recv, and when we found io.eof (stream closed), we needed to send the final response to the client via stream.sendandClose and close the Recv waiting on the other side.

client:

package main

import (
	"context"
	"google.golang.org/grpc"
	"log"
	pb "rpc/proto" // Set the reference alias
)

SayHello calls the Hello method on the server
func SayHello(client pb.HelloServiceClient, r *pb.String) error {
	stream, _ := client.Hello(context.Background())
	for n := 0; n < 6; n++ {
		_ = stream.Send(r)
	}
	resp, _ := stream.CloseAndRecv()

	log.Printf("resp err: %v", resp)
	return nil
}

func main(a) {
	conn, err := grpc.Dial("localhost:1234", grpc.WithInsecure())
	iferr ! =nil {
		log.Fatal("dialing err:", err)
	}
	defer conn.Close()

	// Establish a gRPC connection
	client := pb.NewHelloServiceClient(conn)

	// Create a send structure
	req := pb.String{
		Value: "stream server grpc ",
	}
	SayHello(client, &req)
}

Copy the code

Stream. CloseAndRecv on the Server side is used with stream.SendAndClose on the Client side.

Start the server. Start the client. The result is as follows:

$ go run server.go
2021/11/17 13:26:34  net.Listing...
2021/11/17 13:26:44 resp: value:"stream server grpc "
2021/11/17 13:26:44 resp: value:"stream server grpc "
2021/11/17 13:26:44 resp: value:"stream server grpc "
2021/11/17 13:26:44 resp: value:"stream server grpc "
2021/11/17 13:26:44 resp: value:"stream server grpc "
2021/11/17 13:26:44 resp: value:"stream server grpc "
Copy the code
$ go run client.go
2021/11/17 13:26:44 resp err: value:"say.hello"
Copy the code

Bidirectional Streaming RPC: Indicates two-way streaming RPC

Two-way streaming RPC, in which the client initiates a request in streaming mode and the server responds to the request in streaming mode.

The first request must be initiated by the Client, but the specific interaction (who comes first and who comes after, how much to send at a time, how much to respond to, and when to close) depends on how the program is written (you can combine coroutines).

Proto :

syntax = "proto3";

package proto;

message String {
    string value = 1;
}

service HelloService {
    rpc Hello (stream String) returns (stream String){};
}
Copy the code

server:

package main

import (
	"google.golang.org/grpc"
	"io"
	"log"
	"net"
	pb "rpc/proto" // Set the reference alias
)

// HelloServiceImpl defines our service
type HelloServiceImpl struct{}

// Implement the Hello method
func (p *HelloServiceImpl) Hello(stream pb.HelloService_HelloServer) error {
	for {
		_ = stream.Send(&pb.String{Value: "say.hello"})

		resp, err := stream.Recv()
		// Return after receiving
		if err == io.EOF {
			return nil
		}
		iferr ! =nil {
			return err
		}
		log.Printf("resp: %v", resp)
	}
}

func main(a) {
	// Create a gRPC server instance
	grpcServer := grpc.NewServer()
	// Register our service on the gRPC server
	pb.RegisterHelloServiceServer(grpcServer, new(HelloServiceImpl))

	lis, err := net.Listen("tcp".": 1234")
	iferr ! =nil {
		log.Fatal(err)
	}
	log.Println(" net.Listing...")
	err = grpcServer.Serve(lis)
	iferr ! =nil {
		log.Fatalf("grpcServer.Serve err: %v", err)
	}
}
Copy the code

client:

package main

import (
	"context"
	"google.golang.org/grpc"
	"io"
	"log"
	pb "rpc/proto" // Set the reference alias
)

SayHello calls the Hello method on the server
func SayHello(client pb.HelloServiceClient, r *pb.String) error {
	stream, _ := client.Hello(context.Background())
	for n := 0; n <= 3; n++ {
		_ = stream.Send(r)
		resp, err := stream.Recv()
		if err == io.EOF {
			break
		}
		iferr ! =nil {
			return err
		}

		log.Printf("resp err: %v", resp)
	}

	_ = stream.CloseSend()

	return nil
}


func main(a) {
	conn, err := grpc.Dial("localhost:1234", grpc.WithInsecure())
	iferr ! =nil {
		log.Fatal("dialing err:", err)
	}
	defer conn.Close()

	// Establish a gRPC connection
	client := pb.NewHelloServiceClient(conn)

	// Create a send structure
	req := pb.String{
		Value: "stream server grpc ",
	}
	SayHello(client, &req)
}

Copy the code

The server receives data from the client in the loop. If IO.EOF is encountered, the client stream is closed, and if the function exits the server, the client stream is closed

The server stream is closed. The generated returned data is sent to the client through the stream. The sending and receiving of two-way stream data are completely independent behaviors. It is important to note that the sending and receiving operations do not need to correspond one to one. Users can organize the code according to the actual scenario.

Start the server. Start the client. The result is as follows:

$ go run server.go
2021/11/17 15:46:10  net.Listing...
2021/11/17 15:46:19 resp: value:"stream server grpc "
2021/11/17 15:46:19 resp: value:"stream server grpc "
2021/11/17 15:46:19 resp: value:"stream server grpc "
2021/11/17 15:46:19 resp: value:"stream server grpc "
Copy the code
$ go run client.go
2021/11/17 15:46:19 resp err: value:"say.hello"
2021/11/17 15:46:19 resp err: value:"say.hello"
2021/11/17 15:46:19 resp err: value:"say.hello"
2021/11/17 15:46:19 resp err: value:"say.hello"
Copy the code