导语: 本文以幽默诙谐的方式,介绍gRPC的4种client-server服务模式的开发实践及应用场景

前言:为什么要写这篇文章?

  • The best way to learn is to teach. gRPC的examples里的例子是一个简易的router,琐碎的业务代码很多,看起来比较绕。于是就自己写一个例子,看看自己是否都将这些知识点掌握了。

  • 谈恋爱的过程,其实跟client-server服务模式非常像。单独讲这4种模式有些无聊,所以就尝试用一种尽量有趣的方式去介绍,顺便也可以作为某些男生的一份简单的恋爱指南。

gRPC client-server服务模式

这里先将重要的结论写出来,方便以后查阅,具体介绍见下文。找不到准确的中文来翻译这几种模式,就保留了英文。

  •  0x1: A simple RPC

    最简单的一发一收的client-server模型。这就是我们用得最多的模式

  •  0x2: A client-to-server streaming RPC

    client先建立长连接,然后发送多个request给server,server最后统一回一个rsp

应用场景:

  1. agent上报CPU,内存等数据到server

  2. 客户端心跳

  3. 客户端并发调用细小粒度的接口。比如有5个后台接口A B C D E,客户端在不同页面,可以调用不同的接口组合。比如在个人页,就调用ABC;在动态页面,就调用CDE,后台都只会有一个rsp。这种模式的好处就是让后台可以将接口的粒度细化,客户端调用灵活,减少重复代码,提高复用率

  • 0x3: A server-to-client streaming RPC

    client先发一个请求到server,然后server不停的回包

应用场景:

  1. 股票app。客户端向服务端发送一个股票代码,服务端就把该股票的实时数据源源不断的返回给客户端

  2. app的在线push。client先发请求到server注册,然后server就可以发在线push了

  • 0x4: A Bidirectional streaming RPC

    建立一个长连接,然后client和server可以随意收发数据

应用场景:

  1. 聊天机器人

  2. 有状态的游戏服务器进行数据交换。比如LOL,王者荣耀等竞技游戏,client和server之间需要非常频繁地交换数据

  • 总结:除了一发一收的模式,client-to-server与server-to-client这两种模式,其实用双向RPC都可以做到。但是双向RPC的编码难度更高(后面例子中可以看到),异常处理也需要更仔细,所以具体使用哪种模式需要根据具体需求来分析

接下来就让我用一个男女生之间的交往故事来说明这4种服务模式。内容纯属虚构,并故意写得比较搞笑。如果有不恰当的描述,请告诉我。

男女生交往之gRPC的4种模式

一些说明

  • Selina:女生名字,client

  • John:男生名字,server

  • 等等,女生是client,男生是server。那么,女生给男生提要求,是不是就是client向server请求数据一样自然!!!!噢噢噢,这应该是我学编程以来,领悟到的最重要的道理吧!!!

基础代码说明

  • client

// 建立跟server的连接    conn, err := grpc.Dial(love_const.Address, grpc.WithInsecure())

(左滑可查看完整代码,下同)

  • server

// 设置监听协议与端口
lis, err := net.Listen("tcp", love_const.Address)    // 初始化gRPC server实例 grpcServer := grpc.NewServer() // 注册命令字与处理函数   love_proto.RegisterBehaviorServer(grpcServer, newServer())  // 启动服务 grpcServer.Serve(lis)

0x1: A simple RPC


  • Selina职场工作不顺,刚被leader说了一顿,又恰好来大姨妈了,心情十分不好,问John:在哪

  • John正在打游戏,非常忙,未察觉出Selina的语气有异样,说:刚起床,在打游戏呢

Selina: "在哪"
Jhon: "刚起床,在打游戏呢"

这种模式就是我们用得最多的模式,一发一收

  • client代码

response, err := client.WhereAreYou(ctx, message)
  • server代码

func (s *loveServer) WhereAreYou(ctx context.Context, message *love_proto.Message) (*love_proto.Response, error) {  rsp := new(love_proto.Response)    rsp.Words = "刚起床,在打游戏呢"   return rsp, nil
}

0x2: A client-to-server streaming RPC


  • Selina开始向John诉苦,说了很多话

  • John忙着打游戏,只看清“我来大姨妈了”,就只回了一句:哦,多喝热水

Selina: "你在干嘛"
Selina: "我不开心"
Selina: "我要和你说话"
Selina: "你怎么还不打电话过来"
Selina: "我来大姨妈了"
Jhon: "哦,多喝热水"

这种模式是client先建立长连接,然后发送多个request给server,server最后统一回一个rsp。

应用场景

  1. agent收集CPU,内存等数据到server

  2. 客户端心跳

  3. 客户端并发调用细小粒度的接口。比如有5个后台接口A B C D E,客户端在不同页面,可以调用不同的接口组合,比如在个人页,就调用ABC;在动态页面,就调用CDE,后台都只会有一个rsp。这种模式的好处就是让后台可以将接口的粒度细化,客户端调用灵活,减少重复代码,提高复用率

  • client代码

// 获取一个stream对象  stream, err := client.ContinuousCall(ctx)  if err != nil {    log.Fatalf("%v.ContinuousCall(_) = _, %v", client, err)  }   // 通过stream来发送多个message for _, message := range messages { fmt.Printf("message words: %s\n", message.Words)  if err := stream.Send(message); err != nil {  log.Fatalf("%v.Send(%v) = %v", stream, message, err) }   }   // 发送EOF给server,然后收取server的回包    reply, err := stream.CloseAndRecv()    if err != nil {    log.Fatalf("%v.CloseAndRecv() got error %v, want %v", stream, err, nil)   }
  • server代码

 for {    // 不断收取client的发包    message, err := stream.Recv()  // 当客户端发送EOF时说明要给回包了    if err == io.EOF {    rsp := new(love_proto.Response)    rsp.Words = "哦,多喝热水"  return stream.SendAndClose(rsp) }   if err != nil {    return err  }   printGirlWords(message.Words)   }

0x3: A server-to-client streaming RPC


  • Selina生气了

  • John先一直想解决方案,然后发现没有回应,就要买礼物,安慰等措施:包治百病

Selina: "这么久不给我打电话,你是不是不爱我了?"
Jhon: "啊,宝贝你怎么了?"
Jhon: "我刚刚在玩游戏,那一局刚开,我走不开啊"
Jhon: "你不能不讲道理啊"
Jhon: "你都20分钟不回我了"
Jhon: "好了,宝贝,我错了,都是我的错"
Jhon: "你在家等我,我过去接你,带你去买包包"

这种模式是client先发一个请求到server,然后server不停的回包

应用场景

  1. 股票app。客户端向服务端发送一个股票代码,服务端就把该股票的实时数据源源不断的返回给客户端

  2. app的在线push。client先发请求到server注册,然后server就可以发在线push了

  • client代码

// 获取stream对象,并发送一个消息    stream, err := client.LoveOrNot(ctx, message)  if err != nil {    log.Fatalf("%v.LoveOrNot(_) = _, %v", client, err)   }   for {   // 不断收取server回包 response, err := stream.Recv() // EOF表示server发包结束  if err == io.EOF {    break   }   if err != nil {    log.Fatalf("%v.LoveOrNot(_) = _, %v", client, err)   }   log.Printf("rsp: %s", response.Words) }
  • server代码

for _, response := range responses { // 不停向client发消息 if err := stream.Send(response); err != nil { return err  }   }

0x4: A Bidirectional streaming RPC


  • John道歉,买礼物,Selina不再生气,于是开始聊天

Selina: "好呀好呀"
Jhon: "宝贝我很快就到啦"
Selina: "等我化妆"
Jhon: "宝贝我很快就到啦"
Selina: "亲爱的你最好啦"
Jhon: "宝贝我很快就到啦"
Selina: "么么哒"
Jhon: "宝贝我很快就到啦"

这种模式就是建立一个长连接,然后client和server可以随意收发数据

应用场景

  1. 聊天机器人

  2. 有状态的游戏服务器进行数据交换。比如LOL,王者荣耀等竞技游戏,client和server之间需要非常频繁地交换数据

  • client代码

 // 获取stream对象  stream, err := client.LoveChat(ctx)
if err != nil {    log.Fatalf("%v.LoveChat(_) = _, %v", client, err)    }   // 这个管道没有太多实际意义,只是为了让client将rsp都收完整  waitc := make(chan struct{})   go func() { for {   // 不停地收server的包 response, err := stream.Recv() // server回包EOF,然后关闭管道    if err == io.EOF {    // read done.   close(waitc)    log.Printf("EOF return")  return  }   if err != nil {    log.Fatalf("Failed to receive a note : %v", err)  }   log.Printf("rsp: %s", response.Words) }   }() // 每隔一秒向server发一个消息,模拟聊天场景   for _, message := range messages { time.Sleep(1 * time.Second) if err := stream.Send(message); err != nil {  log.Fatalf("Failed to send a message: %v", err)   }   }   // 这里告诉server: client已经将数据发完了(其实就是给server发一个EOF),server会返回一个io.EOF   stream.CloseSend()  <-waitc
  • server代码

 for {   // 不断收取client发包 message, err := stream.Recv()  if err == io.EOF {    return nil  }   if err != nil {    return err  }   for _, response := range responses {   // 给client发包    if err := stream.Send(response); err != nil { return err  }   }   }

男生们看过来,看过来

  • 既然标题写了“用gRPC教程序员谈恋爱”,那么肯定就得给点干货。女生可能天生比男生更感性一些,所以当女生在倾诉问题的时候,千万不要只去想解决方案,而是要尽快地安慰女生,倾听她的吐槽,顺着她的思路去稍微吐槽下。可以换位思考,如果你自己心情不好的时候,肯定也想有人来安慰,而不是想听到”你要看开一点,这样工作效率才会高”之类的解决方案的话

  • 在倾听和安慰之后,然后把问题解决,或者帮助女生把问题解决。做和说同样重要。

程序员如何用gRPC谈一场恋爱相关推荐

  1. 程序员如何用技术变现

    如今的中国人,不再羞于谈钱,甚至有些过度追求金钱,这是时代的进步,而程序员拥有编写代码的手艺,作为一名匠人,当然可以通过手艺来赚钱.谈到程序员的变现途径,我们通常会想到的方法有: 接项目 开发小软件 ...

  2. 程序员如何用糖果实现盈利 - [别人家的程序员01]

    程序员如何用糖果实现盈利 - [别人家的程序员01] 程序员如何用糖果实现盈利 - [别人家的程序员01] 前言 CandyJapan 网站如何从零走到今天 平台收支状况 如何做分析.写代码 总结 程 ...

  3. 程序员如何用“心“表白(结尾附源码)

    写在前面:博主是一只经过实战开发历练后投身培训事业的"小山猪",昵称取自动画片<狮子王>中的"彭彭",总是以乐观.积极的心态对待周边的事物.本人的技 ...

  4. 编程开发学习笔记之程序员如何用1年时间获得3年成长(图)

    2019独角兽企业重金招聘Python工程师标准>>> 编程开发学习笔记之程序员如何用1年时间获得3年成长(图) 前言 这世界存在这么一个银行,你一出生,就自动享有这家银行为你开设的 ...

  5. 漫谈程序员(十八)浅谈谷歌用户体验设计准则

    #漫谈程序员(十八)浅谈谷歌用户体验设计准则 ##谷歌的愿景   Google用户体验团队致力于创建有用的(useful).快速的(fast).简单的(simple).有吸引力的(engaging). ...

  6. python程序员爬取分析20万场吃鸡数据,带妹吃鸡,终成人生赢家

    首先,神枪镇楼 python程序员爬取分析20万场吃鸡数据,带妹吃鸡,终成人生赢家 吃鸡,撩妹神器 吃鸡游戏受到很多年轻人的喜爱,用户量也非常大.有很多地图,场景逼真,技术玩法,增加了游戏可玩性.而且 ...

  7. python绘制生日快乐图片_程序员如何用代码祝自己生日快乐(多用模板)

    原标题:程序员如何用代码祝自己生日快乐(多用模板) 本文教你如何用代码为自己庆祝生日,当然你也可以用来讨好女神,具体如何应用大家可以发散思维,例如情人节给暗恋的女孩发一个 JS 文件过去表白,或者给女 ...

  8. outlook搜索栏跑到上面去了_都市农园 周末去谈一场恋爱,顺便买回一座花园

    点击蓝字关注我们 8月9日上午,"家庭菜园群"第三次线下交流活动在红尘虫子家举行,主题是分享她家的都市农园规划.设计. 陈科 摄 可来到她家,大家瞬间就被那分区明朗.物种丰富.景致 ...

  9. 软件随想录:程序员部落酋长Joel谈软件(阮一峰译)-3

    3. 寻找优秀的程序员之实战指南 2006年9月7日,星期四 你是一个雇主.你在所有正确的地方刊登了招聘广告,你有一个完善的实习生制度,你面试了所有你想要的人.但是很不幸,如果优秀的程序员不愿意为你工 ...

最新文章

  1. 用 Java 训练深度学习模型,原来这么简单
  2. 在Visual Studio 2019中修改项目名
  3. ITK:从标量图像创建矢量图像
  4. 深入了解C#系列:谈谈C#中垃圾回收与内存管理机制
  5. 时隔多日,旧域名重用,niceyoo博客上线
  6. ueditor 在线附件和在线图片路径错误BUG补丁
  7. 【LeetCode】【HOT】23. 合并K个升序链表(递归+分治)
  8. mysql是单核吗_一次单核CPU占用过高问题的处理
  9. 真相 | 14 岁编程神童谎言坐实,除了谴责我们该反思什么?
  10. the database profile could not loaded. Check log for details
  11. mysql 关系图 工具_ER图绘制软件-DbSchema数据库关系图设计器下载v8.1.7-领航下载站...
  12. 红帽9linux安装ios,红帽linux9.0安装教程
  13. win10家庭版,双击bat文件无法运行_20200120
  14. Rabbit基础概念
  15. Docker一键部署cloud-torrent实现不限速下载BT文件
  16. 五一南京-无丝竹无案牍
  17. 异构网络-元图、知识图谱
  18. 使用微信web开发者工具调试接口数据【开发记录】
  19. 用代码作图?就是玩!!
  20. python小游戏——跑酷小恐龙代码开源

热门文章

  1. Redis的数据类型之String
  2. 《JavaScript高级程序设计》笔记:JavaScript简介(一)
  3. Easy Problem 2 奇妙的数字
  4. http://jingyan.baidu.com/article/dca1fa6fa07000f1a44052f6.html
  5. IIS如何配置可以下载APK、IPA文件
  6. 使用scrollIntoView方法解决抛锚定位时网页往上跳的问题
  7. Google 翻译,梦想与现实的距离有多远
  8. 目标检测常用数据集格式
  9. [SDWC2018 Day1]网格
  10. windows终止处理程序( __try __finally) 简单解析