grpc服务端和客户端传数据的四种方式

尝试四种C/S数据传输方式

给person.proto定上四个方法

message PersonReq {
	string name = 1;
	int32 age = 2;
}

message PersonRes {
	string name = 1;
	int32 age = 2;
}

service SearchService {
	rpc Search(PersonReq) returns (PersonRes); //传统的,即刻响应
	rpc SearchIn(stream PersonReq) returns (PersonRes); //入参为流
	rpc SearchOut(PersonReq) returns (stream PersonRes); //出参为流
	rpc SearchIo(stream PersonReq) returns (stream PersonRes); //入参为流
}
  1. 传统的方式

    这里就是客户端调用,然后服务端返回,很简单

    server:

    func (*personServe) Search(ctx context.Context, req *person.PersonReq) (*person.PersonRes, error) {
    	name := req.GetName()
    	res := &person.PersonRes{Name: "我收到了" + name + "的消息"}
    	return res, nil
    }
    

    client:

    l, err := grpc.Dial("localhost:8888", grpc.WithInsecure())
    if err != nil {
    	log.Println(err.Error())
    }
    client := person.NewSearchServiceClient(l)
    res, err := client.Search(context.Background(), &person.PersonReq{Name: "ymk"})
    if err != nil {
    	log.Println(err.Error())
    }
    fmt.Println(res)
    
  2. 入参为流

    server:

    func (*personServe) SearchIn(server person.SearchService_SearchInServer) error {
    	//这里服务端不断接收客户端的消息,等服务端说结束了,就就结束了
    	for {
    		req, err := server.Recv()
    		fmt.Println(req)
    		if err != nil {
    			server.SendAndClose(&person.PersonRes{Name: "完成了"})
    			break
    		}
    	}
    	return nil
    }
    

    服务端不断接收客户端消息,然后打印,如果客户端终止了连接,err就会 != nil,然后就向客户端发送完成了

    client:

    c, err := client.SearchIn(context.Background())
    if err != nil {
    	log.Panicln(err.Error())
    }
    i := 0
    //这里是,客户端给服务端发送10次消息,然后关闭连接。
    for {
    	if i > 10 {
    		res, _ := c.CloseAndRecv()
    		fmt.Println(res)
    		break
    	}
    	time.Sleep(time.Second)
    	c.Send(&person.PersonReq{Name: "我是进来的信息"})
    	i++
    }
    

    客户端会像服务端发送10次消息,然后通知关闭连接。

    运行结果,

    服务端:

    image-20220708110225388

    客户端:

    image-20220708110236840

  3. 出参为流

    server:

    服务端就发十个消息

    func (*personServe) SearchOut(req *person.PersonReq, server person.SearchService_SearchOutServer) error {
    	name := req.Name
    	i := 0
    	for {
    		if i > 10 {
    			break
    		}
    		time.Sleep(time.Second)
    		server.Send(&person.PersonRes{Name: "我拿到了" + name})
    		i++
    	}
    	return nil
    }
    

    client

    客户端不停接收

    c, err := client.SearchOut(context.Background(), &person.PersonReq{Name: "ymk"})
    if err != nil {
    	log.Println(err.Error())
    }
    for {
    	req, err := c.Recv()
    	if err != nil {
    		log.Panicln(err.Error())
    		break
    	}
    	fmt.Println(req)
    }
    

    image-20220708150400308

  4. 出入均为流

    server

    这里服务端做的事情就是接收进来的东西,原封不动地扔回去

    这里起两个协程,一边接收,一边发送,通过channel通信

    func (*personServe) SearchIo(server person.SearchService_SearchIoServer) error {
    
    	str := make(chan string)
    	i := 0
    	go func() {
    		for {
    			i++
    			req, _ := server.Recv()
    			if i > 10 {
    				str <- "END"
    				break
    			}
    			str <- req.Name
    		}
    	}()
    	for {
    		s := <-str
    		if s == "END" {
    			break
    		}
    		server.Send(&person.PersonRes{Name: s})
    	}
    	return nil
    }
    

    client

    这里起两个

    var wg sync.WaitGroup
    wg.Add(2)
    c, _ := client.SearchIo(context.Background())
    go func() {
    	for {
    		time.Sleep(time.Second)
    		err := c.Send(&person.PersonReq{Name: "ymk"})
    		if err != nil {
    			wg.Done()
    			break
    		}
    	}
    }()
    go func() {
    	for {
    		res, err := c.Recv()
    		if err != nil {
    			log.Println(err.Error())
    			wg.Done()
    			break
    		}
    		fmt.Println(res)
    	}
    }()
    wg.Wait()
    

    image-20220708153825537

posted @ 2022-07-08 15:55  博客是个啥?  阅读(828)  评论(0编辑  收藏  举报