1、proto文件
syntax = "proto3";
package pro;
option go_package = "./";
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;
}
2、server代码
package main
import (
"fmt"
"google.golang.org/grpc"
"log"
"net"
"pro"
"sync"
"time"
)
const PORT = "localhost:50051"
type server struct {
}
// 服务端 单向流
func (s *server) GetStream(req *pro.StreamReqData, res pro.Greeter_GetStreamServer) error {
i := 0
for {
i++
res.Send(&pro.StreamResData{Data: fmt.Sprintf("%v", time.Now().Unix())})
time.Sleep(1 * time.Second)
if i > 10 {
break
}
}
return nil
}
// 客户端 单向流
func (s *server) PutStream(cliStr pro.Greeter_PutStreamServer) error {
for {
if tem, err := cliStr.Recv(); err == nil {
log.Println(tem)
} else {
log.Println("break, err :", err)
break
}
}
return nil
}
// 客户端服务端 双向流
func (s *server) AllStream(allStr pro.Greeter_AllStreamServer) error {
wg := sync.WaitGroup{}
wg.Add(2)
go func() {
for {
data, _ := allStr.Recv()
log.Println(data)
}
wg.Done()
}()
go func() {
for {
allStr.Send(&pro.StreamResData{Data: "ssss"})
time.Sleep(time.Second)
}
wg.Done()
}()
wg.Wait()
return nil
}
func main() {
//监听端口
lis, err := net.Listen("tcp", PORT)
if err != nil {
return
}
//创建一个grpc 服务器
s := grpc.NewServer()
//注册事件
pro.RegisterGreeterServer(s, &server{})
//处理链接
s.Serve(lis)
}
3、服务器流式
3.1 客户端代码
func main() {
//通过grpc 库 建立一个连接
conn, err := grpc.Dial(ADDRESS, grpc.WithInsecure())
if err != nil {
return
}
defer conn.Close()
//通过刚刚的连接 生成一个client对象。
c := pro.NewGreeterClient(conn)
//调用服务端推送流
reqstreamData := &pro.StreamReqData{Data: "aaa"}
res, _ := c.GetStream(context.Background(), reqstreamData)
for {
aa, err := res.Recv()
if err != nil {
log.Println(err)
break
}
log.Println(aa)
}
}
3.2 客户端报文
客户端发出了一个HEADER帧和一个DATA帧,这个HEADER帧内容为:
flag中出现了END_HEADERS, 用于指示该 frame 包含了整个 header block (Header Block Fragment,头部压缩信息)的数据, 其后不会跟随 CONTINUATION frame。
te:trailers表明要求服务器响应带上Trailer。
DATA帧内容为(有End flag):
3.3 服务器报文
服务器回复了一个HEADER帧和数个DATA帧:
最后一个DATA帧:
流式的最后一个DATA帧并没有设置end flag,这是因为发送这个DATA帧时grpc并不知道这是最后一个。
最后是一个HEADER帧:
最后一个HEADER帧携带了END stream flag,但并没有携带trailer。