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); //入参为流
}
-
传统的方式
这里就是客户端调用,然后服务端返回,很简单
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)
-
入参为流
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次消息,然后通知关闭连接。
运行结果,
服务端:
客户端:
-
出参为流
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) }
-
出入均为流
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()
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)