go語言使用GRPC流處理模式

go語言使用GRPC流處理模式

標籤(空格分隔): go,grpc

proto文件

syntax = "proto3";
package four_kinds_method.v1;
option go_package="go-example/grpc/four_kinds_method/proto;four_kinds_method_pb";


// gRPC 允許您定義四種服務方法
// 1. 一元 RPC,其中客戶端向服務器發送單個請求並返回單個響應,就像普通函數調用一樣
// rpc SayHello(HelloRequest) returns (HelloResponse);
// 2. 服務器流式處理 RPC,其中客戶端向服務器發送請求並獲取流以讀回消息序列。客戶端從返回的流中讀取,直到沒有更多消息。gRPC 保證單個 RPC 調用中的消息排序
// rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse);
// 3. 客戶端流式處理 RPC,其中客戶端寫入一系列消息並將其發送到服務器,再次使用提供的流。客戶端完成消息寫入後,它將等待服務器讀取消息並返回其響應。同樣,gRPC 保證單個 RPC 調用中的消息排序
// rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse);
// 4. 雙向流式處理 RPC,其中雙方使用讀寫流發送一系列消息。這兩個流獨立運行,因此客戶端和服務器可以按照它們喜歡的任何順序進行讀取和寫入:例如,服務器可以等待接收所有客戶端消息,然後再寫入響應,或者它可以交替讀取消息然後寫入消息,或者讀取和寫入的某種其他組合。保留每個流中消息的順序
// rpc BidiHello(stream HelloRequest) returns (stream HelloResponse);


// 生成pb文件: protoc --go_out=plugins=grpc:. --go_opt=paths=source_relative ./four_kinds_method.proto

message StreamRequest {
  string data = 1;
}

message StreamResponse {
  string data = 1;
}

service Greeter {
  // 服務端流
  rpc GetStream(StreamRequest) returns (stream StreamResponse);
  // 客戶端流
  rpc PutStream(stream StreamRequest) returns (StreamResponse);
  // 雙向流
  rpc AllStream(stream StreamRequest) returns (stream StreamResponse);
}

server實現

package api

import (
	"fmt"
	four_kinds_method_pb "go-example/grpc/four_kinds_service_method/proto"
	"sync"
	"time"
)

type Service struct {
}

// GetStream 服務端流模式
func (s *Service) GetStream(req *four_kinds_method_pb.StreamRequest, res four_kinds_method_pb.Greeter_GetStreamServer) error {
	i := 0
	for true {
		i++
		res.Send(&four_kinds_method_pb.StreamResponse{
			Data: fmt.Sprintf("%s, %+v", req.Data, time.Now().Unix()),
		})
		if i >= 10 {
			break
		}
		time.Sleep(time.Second * 2)
	}
	return nil
}

// PutStream 客戶端流模式
func (s *Service) PutStream(clientStream four_kinds_method_pb.Greeter_PutStreamServer) error {
	for {
		recv, err := clientStream.Recv()
		if err != nil {
			fmt.Println("PutStreamErr: ", err)
			break
		} else {
			fmt.Println("PutStreamRecv: ", recv.Data)
		}
	}
	return nil
}

// AllStream 雙向流模式
func (s *Service) AllStream(allStream four_kinds_method_pb.Greeter_AllStreamServer) error {

	var wg sync.WaitGroup
	wg.Add(2)
	go func() {
		defer wg.Done()
		for {
			recv, err := allStream.Recv()
			if err != nil {
				fmt.Println("服務端接受數據錯誤: ", err)
				break
			} else {
				fmt.Println("服務端接受數據成功: ", recv.Data)
			}

			// break
		}
	}()

	go func() {
		defer wg.Done()
		for {
			allStream.Send(&four_kinds_method_pb.StreamResponse{
				Data: "我是服務端:hello world",
			})
			// break
		}
	}()

	wg.Wait()
	return nil
}

server-main啓動服務

package main

import (
	"go-example/grpc/four_kinds_service_method/api"
	four_kinds_method_pb "go-example/grpc/four_kinds_service_method/proto"
	"go.uber.org/zap"
	"google.golang.org/grpc"
	"net"
)

func main() {

	logger, _ := zap.NewDevelopment()

	server := grpc.NewServer()

	four_kinds_method_pb.RegisterGreeterServer(server, &api.Service{})

	listen, err := net.Listen("tcp", ":6662")
	if err != nil {
		logger.Fatal("net.Listen error", zap.Error(err))
	}
	logger.Info("grpc four_kinds_method service started [127.0.0.1:6662] ")
	err = server.Serve(listen)
	if err != nil {
		logger.Fatal("grpc serve error", zap.Error(err))
	}
}

client

package main

import (
	"context"
	"fmt"
	four_kinds_method_pb "go-example/grpc/four_kinds_service_method/proto"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
)

func main() {

	conn, err := grpc.Dial("127.0.0.1:6662", grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		panic(err)
	}

	client := four_kinds_method_pb.NewGreeterClient(conn)

	//stream, _ := client.GetStream(context.Background(), &four_kinds_method_pb.StreamRequest{Data: "Hello World"})
	//for {
	//	recv, err := stream.Recv()
	//	if err != nil {
	//		fmt.Println("err:", err)
	//		break
	//	}
	//	fmt.Println("recv: ", recv)
	//}

	//putStream, err := client.PutStream(context.Background())
	//if err != nil {
	//	panic(err)
	//}
	//
	//i := 0
	//for {
	//	i++
	//	putStream.Send(&four_kinds_method_pb.StreamRequest{
	//		Data: "Hello World" + strconv.Itoa(i),
	//	})
	//	time.Sleep(time.Second * 2)
	//	if i > 10 {
	//		break
	//	}
	//}

	stream, err := client.AllStream(context.TODO())
	if err != nil {
		fmt.Println("err1:", err)
	}
	//for {

	err = stream.Send(&four_kinds_method_pb.StreamRequest{
		Data: "hello php",
	})
	fmt.Println("err:", err)
	stream.CloseSend()
	//}

	//go func() {
	//	for {
	//		recv, _ := stream.Recv()
	//		fmt.Println(recv)
	//	}
	//}()
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章