废话不多说,直接上代码:
1.项目目录结构

2.proto 代码
服务端server_stream.proto
Go
syntax = "proto3";
package server;
// 包名
option go_package = "/server";
//定义rpc服务
service ServerStream {
//定义函数体 主要stream
rpc DownFile(ReqServer) returns (stream ResServer);
}
message ReqServer {
string name = 1;
}
message ResServer {
bytes content = 1;
}
客户端client_stream.proto
Go
syntax = "proto3";
package client;
option go_package = "/client";
// 定义服务
service ClientStream {
// 定义函数体 主要stream
rpc UploadFile(stream ReqClient) returns (ResClient);
}
message ReqClient {
string name = 1;
bytes content = 2;
}
message ResClient {
string name = 1;
}
3.客户端和服务端代码实现
客户端grpc_client_stream.go
Go
package main
import (
"bufio"
"context"
"fmt"
"io"
"log"
"os"
"project09/grpc/proto/stream/client"
"project09/grpc/proto/stream/server"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)
func main() {
addr := ":8010"
// 创建一个客户端连接 且不使用安全证书来实现
conn, err := grpc.NewClient(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatalf("grpc connect addr [%s] 连接失败%s", addr, err)
}
defer conn.Close()
downFile(conn)
uploadFile(conn)
}
func downFile(conn *grpc.ClientConn) {
// 服务端流式 下载
c := server.NewServerStreamClient(conn)
stream, err := c.DownFile(context.Background(), &server.ReqServer{
Name: "james",
})
if err != nil {
return
}
file, err := os.OpenFile("./statics/down_music.mp4", os.O_CREATE|os.O_WRONLY, 0600)
if err != nil {
log.Fatalln(err)
}
defer file.Close()
writer := bufio.NewWriter(file)
for {
response, e := stream.Recv()
if e == io.EOF {
break
}
writer.Write(response.Content)
}
writer.Flush()
fmt.Println("客户端下载成功")
}
func uploadFile(conn *grpc.ClientConn) {
// 客户端流式 上传
s := client.NewClientStreamClient(conn)
stream, err := s.UploadFile(context.Background())
if err != nil {
log.Fatalln(err)
}
file, err := os.Open("./statics/music.mp4")
if err != nil {
log.Fatalln(err)
}
defer file.Close()
// 分片读取
for {
buf := make([]byte, 32)
_, e := file.Read(buf)
if e != nil {
break
}
if e == io.EOF {
break
}
stream.Send(&client.ReqClient{
Content: buf,
})
}
res, e2 := stream.CloseAndRecv()
if e2 != nil {
fmt.Println(res)
}
fmt.Println("客户端上传成功")
}
服务端grpc_server_stream.go
Go
package main
import (
"bufio"
"fmt"
"io"
"log"
"net"
"os"
"project09/grpc/proto/stream/client"
"project09/grpc/proto/stream/server"
"google.golang.org/grpc"
)
type ServerStream struct {
}
func (s *ServerStream) DownFile(request *server.ReqServer, stream server.ServerStream_DownFileServer) error {
fmt.Println("下载...")
file, err := os.Open("./statics/music.mp4")
if err != nil {
log.Fatalln(err)
}
defer file.Close()
// 分片读取
for {
buf := make([]byte, 32)
_, err := file.Read(buf)
if err != nil {
break
}
if err == io.EOF {
break
}
stream.Send(&server.ResServer{
Content: buf,
})
}
return nil
}
type ClientStream struct {
}
func (c *ClientStream) UploadFile(stream client.ClientStream_UploadFileServer) error {
fmt.Println("上传...")
file, err := os.OpenFile("./statics/upload_music.mp4", os.O_CREATE|os.O_WRONLY, 0600)
if err != nil {
log.Fatalln(err)
}
defer file.Close()
writer := bufio.NewWriter(file)
for {
response, err := stream.Recv()
if err == io.EOF {
break
}
writer.Write(response.Content)
}
writer.Flush()
stream.SendAndClose(&client.ResClient{
Name: "上传完毕",
})
return nil
}
type BothStream struct {
}
func main() {
listen, err := net.Listen("tcp", ":8010")
if err != nil {
fmt.Println("Fail to listen")
}
s := grpc.NewServer()
// 将结构体注册为grpc服务
server.RegisterServerStreamServer(s, &ServerStream{})
client.RegisterClientStreamServer(s, &ClientStream{})
fmt.Println("grpc stream server running :8010")
// 开始处理客户端请求
s.Serve(listen)
}
4.运行相关命令
proto生成编译的go文件
bash
### 服务端流式
protoc -I . --go_out=plugins=grpc:./grpc/proto/stream .\grpc\proto\stream\server\server_stream.proto
### 客户端流式
protoc -I . --go_out=plugins=grpc:./grpc/proto/stream .\grpc\proto\stream\client\client_stream.proto
启动服务命令
bash
## 服务端
go run .\grpc\server\stream\grpc_server_stream.go
## 客户端
go run .\grpc\client\stream\grpc_client_stream.go
以上案例是简单实现客户端流式传输和服务端流式传输,基于grpc性能调优,要根据自己的业务而定。
环境安装配置可参考上篇文章。《Golang Protoc Grpc实现微服务通信》