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