grpc学习golang版( 六、服务器流式传输 )

avatar
作者
猴君
阅读量:0

系列文章目录
第一章grpc基本概念与安装
第二章grpc入门示例
第三章proto文件数据类型
第四章多服务示例
第五章多proto文件示例
第六章服务器流式传输
第七章客户端流式传输
第八章双向流示例


文章目录


一、前言

前面我们一直在讲的是服务端、客户端一问一答,最普通且常用的RPC服务。接下来本文介绍的是服务器流式传输。主要应用场景就是客户端请求服务端,从服务端下载视频、文件、图片等等。

二、定义proto文件

新建stream.proto文件

// 指定proto版本 syntax = "proto3"; // 指定默认包名 package stream_proto; // 指定golang包名 option go_package = "/stream_proto";  //定义个流服务,叫什么名字无所谓 service ServiceStream {   //下载文件,关键字stream   rpc DownloadFile(Request)returns(stream FileResponse){} } //请求参数 message Request{   string name = 1; }  //文件回调参数 message FileResponse{   //字节数据类型,即文件内容、数据   bytes content =1; } 

go_grpc_study/example_4/grpc_proto目录下新建Terminal,执行生成文件,命令如下

protoc --go_out=. --go-grpc_out=. ./stream.proto 

目录结构变更后为

具体步骤如下:

  • 1)定义回调message结构体FileResponse,使用bytes数据类型
  • 2)定义ServiceStream服务
  • 2)在服务里面,定义rpc方法DownloadFile,使用关键词stream回调FileResponse结构体

三、拷贝任意文件进项目

任意文件,可以是视频、音频、图片、文档等等,不做限制。这里以一张png图片为例。
新建static目录,拷贝一张grpc.pngstatic目录
图片如下:

目录结构如下

四、编写server服务端

新建server目录,新建main.go文件
目录结构如下

编写server/main.go文件

package main  import ( 	"fmt" 	"go_grpc_study/example_4/grpc_proto/stream_proto" 	"google.golang.org/grpc" 	"io" 	"log" 	"net" 	"os" )  //服务端流式  // 新版本 gRPC 要求必须嵌入 UnimplementedGreeterServer 结构体 type ServiceStream struct { 	stream_proto.UnimplementedServiceStreamServer }  func (ServiceStream) DownloadFile(request *stream_proto.Request, stream stream_proto.ServiceStream_DownloadFileServer) error { 	fmt.Println("DownloadFile", request) 	//分片读的方式读取图片 	file, err := os.Open("../static/grpc.png") 	if err != nil { 		return err 	} 	defer file.Close() 	for { 		buf := make([]byte, 1024) 		_, err = file.Read(buf) 		//当读取完后跳出循环 		if err == io.EOF { 			break 		} 		//出现异常后跳出循环 		if err != nil { 			break 		} 		stream.Send(&stream_proto.FileResponse{ 			Content: buf, 		}) 	}  	return nil }  func main() { 	// 监听端口 	listen, err := net.Listen("tcp", ":8080") 	if err != nil { 		log.Fatal(err) 	} 	// 创建一个gRPC服务器实例。 	s := grpc.NewServer() 	// 将server结构体注册为gRPC服务。 	stream_proto.RegisterServiceStreamServer(s, &ServiceStream{}) 	fmt.Println("grpc server running :8080") 	// 开始处理客户端请求。 	err = s.Serve(listen) } 

具体步骤如下:

  • 1)定义1个结构体,结构体名称无所谓,必须包含stream_proto.UnimplementedServiceStreamServer 对象
  • 2)实现 .proto文件中定义的API即DownloadFile下载文件方法
  • 3)分片读的方式读取图片,并把图片数据响应给客户端,每次1024个字节数据
  • 4)将服务描述及其具体实现注册到 gRPC

五、编写client客户端

新建client目录,新建main.go文件
目录结构如下

编写clinet/main.go文件

package main  import ( 	"bufio" 	"context" 	"fmt" 	"go_grpc_study/example_4/grpc_proto/stream_proto" 	"google.golang.org/grpc" 	"google.golang.org/grpc/credentials/insecure" 	"io" 	"log" 	"os" )  func main() { 	addr := ":8080" 	// 使用 grpc.Dial 创建一个到指定地址的 gRPC 连接。 	// 此处使用不安全的证书来实现 SSL/TLS 连接 	conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials())) 	if err != nil { 		log.Fatalf(fmt.Sprintf("grpc connect addr [%s] 连接失败 %s", addr, err)) 	} 	defer conn.Close()  	client := stream_proto.NewServiceStreamClient(conn) 	//发送消息给服务端 	stream, err := client.DownloadFile(context.Background(), &stream_proto.Request{ 		Name: "周八", 	}) 	//缓冲写的方式另存为新的图片 	//os.O_CREATE : 创建并打开一个新文件 	//os.O_TRUNC :打开一个文件并截断它的长度为零(必须有写权限) 	//os.O_WRONLY :以只写的方式打开 	file, err := os.OpenFile("../static/grpc_new.png", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666) 	if err != nil { 		log.Fatalln(err) 	} 	defer file.Close() 	writer := bufio.NewWriter(file)  	var index int 	for { 		index++ 		response, errRecv := stream.Recv() 		if errRecv == io.EOF { 			break 		} 		if errRecv != nil { 			fmt.Println(errRecv) 			break 		} 		fmt.Printf("第 %d 次,写入 %d 数据\n", index, len(response.Content)) 		writer.Write(response.Content) 	} 	writer.Flush() } 

具体步骤如下:

  • 1)首先使用 grpc.Dial()gRPC 服务器建立连接
  • 2)使用 stream_proto.NewServiceStreamClient(conn)初始化客户端
  • 3)通过客户端调用ServiceAPI方法client.DownloadFile,并得到stream对象
  • 4)通过stream对象的Recv()方法得到[]byte数据
  • 5)通过缓冲写的方式另存为新的图片grpc_new.png

六、测试

server目录下,启动服务端

go run main.go 

clinet目录下,启动客户端

go run main.go 

服务端运行结果

客户端运行结果。我这个图片是119808 字节,最后走了 117 次,写入1024 数据

客户端下载的图片保存结果

六、示例代码

go_grpc_study:grpc学习golang版


完成ヾ(◍°∇°◍)ノ゙

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!