gRPC-05 双端流的实现

20 篇文章 11 订阅

代码地址

https://github.com/wanmei002/grpc-learn/tree/master/ch04

双端流的描述

客户端可以在建立的连接上间歇性发送数据;服务端接收数据,可选择性的发送响应数据给客户端,就像聊天室功能一样。

proto service 声明

service Product {
    rpc AddProduct(stream Order) returns (stream Ret);
}

message Order {
    string name = 1;
    string desc = 2;
    repeated  string items = 3;
}

message Ret {
    int32 code = 4;
    int64 orderId= 5;
    string msg = 6;
}

代码实现

服务端代码实现

实现 proto 声明的方法
func (s *server) AddProduct(stream product.Product_AddProductServer) error {
    log.Println("start AddProduct")
    // 开启一个协程 专门发送数据给客户端
    go sendDataToClient(stream)
    for {
        od, err := stream.Recv()
        if err != nil {
            if err == io.EOF {
                log.Println("server stream end")
                
                retLock.Lock()
                for _, v := range RetOrderInfo {
                    err = stream.Send(v)
                    if err != nil {
                        log.Println("server send failed(EOF);err:", err)
                        return err
                    }
                }
                retLock.Unlock()
                log.Println("server send over")
                return nil
            }
            log.Println("server recv failed; err:", err)
            return err
        }
        // 控制开启协程的数量
        <-ch
        // 处理接收的数据的数据
        go processData(od)
    }
}
跑起来
func main() {
    ch = make(chan struct{}, 10)
    for i:=0; i<10; i++ {
        ch <- struct{}{}
    }
    fmt.Println("server ch:", ch)
    ls, err := net.Listen("tcp", ":8093")
    if err != nil {
        log.Println("listen failed; err:", err)
        return
    }
    g := grpc.NewServer()
    product.RegisterProductServer(g, &server{})
    
    log.Println("start server")
    
    if err = g.Serve(ls); err != nil {
        log.Println("server serve failed; err:", err)
    }
}

客户端代码

func main(){
    d, err := grpc.Dial(":8093", grpc.WithInsecure())
    if err != nil {
        log.Println("client dial failed; err:", err)
        return
    }
    defer d.Close()
    
    client := product.NewProductClient(d)
    
    stream, err := client.AddProduct(context.Background())
    if err != nil {
        log.Println("client add product failed; err:", err)
        return
    }
    // 来一个协程专门接收数据
    ctx, closeFunc := context.WithCancel(context.Background())
    go RecvData(stream, closeFunc)
    for i:=0; i<100; i++ {
        o := &product.Order{
            Name: fmt.Sprint("zzh-",i),
            Desc: fmt.Sprint("desc-",i),
            Items: make([]string, 1),
        }
        log.Println("client send data:", o)
        err := stream.Send(o)
        if err != nil {
            log.Println("clinet send failed;err:", err)
        }
    }
    
    err = stream.CloseSend()
    <-ctx.Done()
    fmt.Println("over")
    
}

func RecvData(stream product.Product_AddProductClient, cancelFunc context.CancelFunc) {
    defer cancelFunc()
    for {
        res, err := stream.Recv()
        if err != nil {
            log.Println("client recv failed; err:", err)
            return
        }
        log.Printf("client recv %+v\n", res)
    }
    
    
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值