gRPC的四种数据流

1、简介

srteam 顾名思义就是一种流,可以源源不断的推送数据,很适合传输一些大数据,或者服务端和客户端长时间数据交互,比如客户端可以向服务端订阅一个数据,服务端就可以利用stream ,源源不断地推送数据。

2、四种流模式

2.1 简单模式(Simple RPC)

这种模式最为传统,即客户端发起一次请求,服务端响应一个数据,这和大家平时熟悉的RPC没有什么大的区别,所以不再详细介绍。

2.2 服务端数据流模式(Server-side streaming RPC)

这种模式是客户端发起一次请求,服务端返回一段连续的数据流。典型的例子是客户端向服务端发送一个股票代码,服务端就把该股票的实时数据源源不断的返回给客户端。

2.3 客户端数据流模式(Client-side streaming RPC)

与服务端数据流模式相反,这次是客户端源源不断的向服务端发送数据流,而在发送结束后,由服务端返回一个响应。典型的例子是物联网终端向服务器报送数据。

2.4 双向数据流模式(Bidirectional streaming RPC)

顾名思义,这是客户端和服务端都可以向对方发送数据流,这个时候双方的数据可以同时互相发送,也就是可以实现实时交互。典型的例子是聊天机器人。

3、定义protobuf文件

syntax = "proto3";

option go_package = "../proto";

service Greeter{
  // 服务端流模式
  rpc GetStream(StreamReqData) returns(stream StreamResData);
  // 客户端流模式
  rpc PutStream(stream StreamReqData)returns(StreamResData);
  // 双向流模式
  rpc AllStream(stream StreamReqData)returns(stream StreamResData);
}

message StreamReqData{
  string data = 1;
}

message StreamResData{
  string data = 1;
}

4、生成go的rpc文件

protoc -I . goods.proto --go_out=plugins=grpc:.

服务端

server.go

package main

import (
	"demo/stream_grpc_test/proto"
	"fmt"
	"google.golang.org/grpc"
	"net"
	"sync"
	"time"
)

const PORT = "0.0.0.0:8080"

type Server struct {
}

// GetStream 服务端流模式
func (s *Server) GetStream(req *proto.StreamReqData, res proto.Greeter_GetStreamServer) error {
	i := 0
	for {
		i++
		_ = res.Send(&proto.StreamResData{Data: fmt.Sprintf("%v", time.Now().Unix())})
		time.Sleep(1 * time.Second)
		if i > 10 {
			break
		}
	}

	return nil
}

// PutStream 客户端流模式
func (s *Server) PutStream(cliStr proto.Greeter_PutStreamServer) error {
	for {
		if tem, err := cliStr.Recv(); err == nil {
			fmt.Println(tem)
		} else {
			fmt.Println("break, err :", err)
			break
		}
	}
	return nil
}

// AllStream 双向流模式
func (s *Server) AllStream(allStr proto.Greeter_AllStreamServer) error {
	wg := sync.WaitGroup{}
	wg.Add(2)

	go func() {
		defer wg.Done()
		for i := 0; i < 10; i++ {
			data, _ := allStr.Recv()
			fmt.Println(data)
		}
	}()

	go func() {
		defer wg.Done()
		for i := 0; i < 5; i++ {
			_ = allStr.Send(&proto.StreamResData{
				Data: "jason",
			})
			
			time.Sleep(1 * time.Second)
		}
	}()

	wg.Wait()

	return nil
}

func main() {
	lis, err := net.Listen("tcp", PORT)
	if err != nil {
		panic(err)
	}
	// 创建一个grpc 服务器
	s := grpc.NewServer()
	// 注册事件
	proto.RegisterGreeterServer(s, &Server{})
	// 处理链接
	err = s.Serve(lis)
	if err != nil {
		panic(err)
	}
}

服务端流模式的客户端

client.go

package main

import (
	"context"
	"demo/stream_grpc_test/proto"
	"fmt"
	"google.golang.org/grpc"
	"time"
)

const ADDRESS = "127.0.0.1:8080"

func main() {
	// 通过grpc库建立连接
	conn, err := grpc.Dial(ADDRESS, grpc.WithInsecure())
	if err != nil {
		panic(err.Error())
	}
	defer func() {
		_ = conn.Close()
	}()

	// 获取client对象
	c := proto.NewGreeterClient(conn)

	// 调用服务端推送流
	res, err := c.GetStream(context.Background(), &proto.StreamReqData{Data: "aaa"})
	if err != nil {
		panic(err.Error())
	}
	for {
		getData, err := res.Recv()
		if err != nil {
			fmt.Println(err)
			break
		}

		fmt.Println(getData)
	}

	// 延迟,防止程序直接退出
	time.Sleep(30 * time.Second)
}

在这里插入图片描述

客户端流模式的客户端

client.go

package main

import (
	"context"
	"demo/stream_grpc_test/proto"
	"google.golang.org/grpc"
	"time"
)

const ADDRESS = "127.0.0.1:8080"

func main() {
	// 通过grpc库建立连接
	conn, err := grpc.Dial(ADDRESS, grpc.WithInsecure())
	if err != nil {
		panic(err.Error())
	}
	defer func() {
		_ = conn.Close()
	}()

	// 获取client对象
	c := proto.NewGreeterClient(conn)

	// 客户端推送流
	putRes, err := c.PutStream(context.Background())
	for i := 0; i < 10; i++ {
		_ = putRes.Send(&proto.StreamReqData{Data: "zhou"})
		time.Sleep(1 * time.Second)
	}

	// 延迟,防止程序直接退出
	time.Sleep(30 * time.Second)
}

在这里插入图片描述

双向流模式的客户端

client.go

package main

import (
	"context"
	"demo/stream_grpc_test/proto"
	"fmt"
	"google.golang.org/grpc"
	"time"
)

const ADDRESS = "127.0.0.1:8080"

func main() {
	// 通过grpc库建立连接
	conn, err := grpc.Dial(ADDRESS, grpc.WithInsecure())
	if err != nil {
		panic(err.Error())
	}
	defer func() {
		_ = conn.Close()
	}()

	// 获取client对象
	c := proto.NewGreeterClient(conn)

	// 双向流
	allStr, err := c.AllStream(context.Background())
	if err != nil {
		panic(err.Error())
	}
	go func() { // 接收服务端推送的数据
		for {
			data, _ := allStr.Recv()
			fmt.Println("接收数据:" + (*data).Data)
		}
	}()

	go func() { // 发送数据到服务端
		for {
			err = allStr.Send(&proto.StreamReqData{Data: "我来自发送"})
			if err != nil {
				fmt.Println(err.Error())
				break
			}
			time.Sleep(1 * time.Second)
		}
	}()

	// 延迟,防止程序直接退出
	time.Sleep(30 * time.Second)
}

在这里插入图片描述
在这里插入图片描述

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JasonHome

你的鼓励是我创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值