go笔记--rpc和grpc使用


rpc

RPC(Remote Procedure Call,远程过程调用)是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络细节的应用程序通信协议。RPC协议构建于TCP或UDP,或者是HTTP上。允许开发者直接调用另一台服务器上的程序,而开发者无需另外的为这个调用过程编写网络通信相关代码,使得开发网络分布式程序在内的应用程序更加容易

RPC采用客户端-服务器端的工作模式,请求程序就是一个客户端,而服务提供程序就是一个服务器端。当执行一个远程过程调用时,客户端程序首先先发送一个带有参数的调用信息到服务端,然后等待服务端响应。在服务端,服务进程保持睡眠状态直到客户端的调用信息到达。当一个调用信息到达时,服务端获得进程参数,计算出结果,并向客户端发送应答信息。然后等待下一个调用。

在Go中,标准库提供的net/rpc包提供了通过网络或其他I/O连接对一个对象的导出方法的访问。服务端注册一个对象,使它作为一个服务被暴露,服务的名字是该对象的类型名。注册之后,对象的导出方法就可以被远程访问。服务端可以注册多个不同类型的对象(服务),但注册具有相同类型的多个对象是错误的。

只有满足如下标准的方法才能用于远程访问,其余方法会被忽略:

--

  • 方法是导出的
  • 方法有两个参数,都是导出类型或内建类型
  • 方法的第二个参数是指针
  • 方法只有一个error接口类型的返回值

也就是说,方法必须看起来像这样:

func (t *T) MethodName(argType T1, replyType *T2) error

其中T、T1和T2都能被encoding/gob包序列化。这些限制即使使用不同的编解码器也适用。(未来,对定制的编解码器可能会使用较宽松一点的限制)

方法的第一个参数代表调用者提供的参数;第二个参数代表返回给调用者的参数。方法的返回值,如果非nil,将被作为字符串回传,在客户端看来就和errors.New创建的一样。如果返回了错误,回复的参数将不会被发送给客户端。

服务端可能会单个连接上调用ServeConn管理请求。更典型地,它会创建一个网络监听器然后调用Accept;或者,对于HTTP监听器,调用HandleHTTP和http.Serve。

想要使用服务的客户端会创建一个连接,然后用该连接调用NewClient。

更方便的函数Dial(DialHTTP)会在一个原始的连接(或HTTP连接)上依次执行这两个步骤。

生成的Client类型值有两个方法,Call和Go,它们的参数为要调用的服务和方法、一个包含参数的指针、一个用于接收接个的指针。

Call方法会等待远端调用完成,而Go方法异步的发送调用请求并使用返回的Call结构体类型的Done通道字段传递完成信号。

除非设置了显式的编解码器,本包默认使用encoding/gob包来传输数据。

一个简单的例子。一个服务端想要导出Arith类型的一个对象:

server.go

  1. package main
  2. import (
  3. //"fmt"
  4. "log"
  5. "net"
  6. "net/http"
  7. "net/rpc"
  8. //"os"
  9. //"time"
  10. "errors"
  11. )
  12. type Args struct {
  13. A, B int
  14. }
  15. type Quotient struct {
  16. Quo, Rem int
  17. }
  18. type Arith int
  19. //乘
  20. func (t *Arith) Multiply(args *Args, reply *int) error {
  21. *reply = args.A * args.B
  22. return nil
  23. }
  24. //除
  25. func (t *Arith) Divide(args *Args, quo *Quotient) error {
  26. if args.B == 0 {
  27. return errors.New("divide by zero")
  28. }
  29. quo.Quo = args.A / args.B
  30. quo.Rem = args.A % args.B
  31. return nil
  32. }
  33. func main() {
  34. arith := new(Arith)
  35. rpc.Register(arith)
  36. rpc.HandleHTTP()
  37. l, e := net.Listen("tcp", ":1234")
  38. if e != nil {
  39. log.Fatal("listen error:", e)
  40. }
  41. http.Serve(l, nil)
  42. }

client.go (sync)

  1. package main
  2. import (
  3. "fmt"
  4. "log"
  5. "net/rpc"
  6. //"time"
  7. )
  8. type Args struct {
  9. A, B int
  10. }
  11. func main() {
  12. client, err := rpc.DialHTTP("tcp", "127.0.0.1:1234")
  13. if err != nil {
  14. log.Fatal("dialing:", err)
  15. }
  16. // Synchronous call
  17. args := &Args{7,8}
  18. var reply int
  19. err = client.Call("Arith.Multiply", args, &reply)
  20. if err != nil {
  21. log.Fatal("arith error:", err)
  22. }
  23. fmt.Printf("Arith: %d*%d=%d", args.A, args.B, reply)
  24. }

client.go (async)

  1. package main
  2. import (
  3. "fmt"
  4. "log"
  5. "net/rpc"
  6. //"time"
  7. )
  8. type Args struct {
  9. A, B int
  10. }
  11. type Quotient struct {
  12. Quo, Rem int
  13. }
  14. func main() {
  15. client, err := rpc.DialHTTP("tcp", "127.0.0.1:1234")
  16. if err != nil {
  17. log.Fatal("dialing:", err)
  18. }
  19. // Synchronous call
  20. /*args := &Args{7,8}
  21. var reply int
  22. err = client.Call("Arith.Multiply", args, &reply)
  23. if err != nil {
  24. log.Fatal("arith error:", err)
  25. }
  26. fmt.Printf("Arith: %d*%d=%d", args.A, args.B, reply)*/
  27. // Asynchronous call
  28. args := &Args{10,3}
  29. quotient := new(Quotient)
  30. divCall := client.Go("Arith.Divide", args, quotient, nil)
  31. replyCall := <-divCall.Done // will be equal to divCall
  32. // check errors, print, etc.
  33. fmt.Println(replyCall.Reply)
  34. }

grpc

gRPC是一个可以在任何环境中运行的现代开源高性能RPC框架。增加了很多扩展接口,例如:可插拔的负载平衡、跟踪、健康体检和身份验证等等。

gRPC默认使用protocol buffers,它是google开源的一套成熟的结构数据序列化机制(当然也可以使用其他数据格式如JSON),可以用proto files创建gRPC服务,用protocol buffers消息类型来定义方法参数和返回类型。

在gRPC客户端可以直接调用不通服务器上的远程程序,就想调用本地程序一样,很容易构建分布式应用和服务。和很多RPC系统一样,服务负责实现定义好的接口并处理客户端请求,客户端根据接口描述直接调用需要的服务。客户端和服务器可以分别使用gRPC支持的不同语言实现。

初次接触就先简单理解为 google rpc 吧。

protobuf 本文就不讲了,直接上例子。

protoc

  1. syntax = "proto3"; //proto版本
  2. package proto;
  3. //请求message
  4. message HelloReq{
  5. string req=1;
  6. }
  7. //响应message
  8. message HelloRep{
  9. string rep=1;
  10. }
  11. //Hello服务
  12. service Hello{
  13. //定义服务中的方法
  14. rpc SayHello(HelloReq)returns (HelloRep){}
  15. }

生成 pb.go

目录结构

go mod 老找不到pb.go 就只好 放各自文件下了, 注意 正常是放在公共文件下的。

go get -u google.golang.org/grpc

server.go

  1. package main
  2. import (
  3. pb "serv/protoc"
  4. "net"
  5. "log"
  6. "golang.org/x/net/context"
  7. "google.golang.org/grpc"
  8. )
  9. //定义一个helloServer并实现约定的接口
  10. type helloService struct{}
  11. func (h helloService) SayHello(ctx context.Context, in *pb.HelloReq) (*pb.HelloRep, error) {
  12. resp := new(pb.HelloRep)
  13. resp.Rep = "reply : " + in.Req
  14. return resp, nil
  15. }
  16. var HelloServer = helloService{}
  17. func main() {
  18. listen, err := net.Listen("tcp", "127.0.0.1:1234")
  19. if err != nil {
  20. log.Fatal("failed to listen")
  21. }
  22. //实现gRPC Server
  23. serv := grpc.NewServer()
  24. //注册helloServer为客户端提供服务
  25. pb.RegisterHelloServer(serv, HelloServer) //内部调用了s.RegisterServer()
  26. serv.Serve(listen)
  27. }

client.go

  1. package main
  2. import (
  3. "fmt"
  4. pb "cli/protoc"
  5. "golang.org/x/net/context"
  6. "google.golang.org/grpc"
  7. )
  8. const (
  9. Address = "127.0.0.1:50052"
  10. )
  11. func main() {
  12. conn, err := grpc.Dial("127.0.0.1:1234", grpc.WithInsecure())
  13. if err != nil {
  14. fmt.Println(err)
  15. }
  16. defer conn.Close()
  17. //初始化客户端
  18. c := pb.NewHelloClient(conn)
  19. req := new(pb.HelloReq)
  20. req.Req = "hello"
  21. r, err := c.SayHello(context.Background(), req)
  22. if err != nil {
  23. fmt.Println(err)
  24. return
  25. }
  26. fmt.Println(r.Rep)
  27. }

go笔记--rpc和grpc使用的更多相关文章

  1. Google 高性能 RPC 框架 gRPC 1.0.0 发布(附精彩评论)

    gRPC是一个高性能.开源.通用的RPC框架,面向移动和HTTP/2设计,是由谷歌发布的首款基于Protocol Buffers的RPC框架. gRPC基于HTTP/2标准设计,带来诸如双向流.流控. ...

  2. 开源RPC(gRPC/Thrift)框架性能评测

    海量互联网业务系统只能依赖分布式架构来解决,而分布式开发的基石则是RPC:本文主要针对两个开源的RPC框架(gRPC. Apache Thrift),以及配合GoLang.C++两个开发语言进行性能对 ...

  3. Python RPC 之 gRPC

    gRPC 简介: gRPC 是一款高性能.开源的 RPC 框架,产自 Google,基于 ProtoBuf 序列化协议进行开发,支持多种语言(Golang.Python.Java等),本篇只介绍 Py ...

  4. RabbitMQ 笔记-RPC

    RabbitMQ中实现RPC的机制是: 客户端发送请求(消息)时,在消息的属性(MessageProperties,在AMQP协议中定义了14中properties,这些属性会随着消息一起发送)中设置 ...

  5. FastSocket学习笔记~RPC的思想,面向对象的灵活

    首先非常感谢这位来自新浪的老兄,它开发的这个FastSocket非常不错,先不说性能如何,单说它的使用方式和理念上就很让人赞口,从宏观上看,它更像是一种远程过程的调用RPC,即服务器公开一些命令,供客 ...

  6. Dubbo学习笔记-RPC扩展和本地Mock

    1.Dubbo介绍 Dubbo,一个是一款高性能Java RPC框架.私以为有中文官方文档,就不再重复介绍了 2.RPC扩展-本地存根stub RPC扩展功能:提前效验参数,缓存调用结果,日志记录等等 ...

  7. gRPC:Google开源的基于HTTP/2和ProtoBuf的通用RPC框架

    gRPC:Google开源的基于HTTP/2和ProtoBuf的通用RPC框架 gRPC:Google开源的基于HTTP/2和ProtoBuf的通用RPC框架 Google Guava官方教程(中文版 ...

  8. RPC 实战与原理 精简版

    什么是 RPC? RPC 有什么作用? RPC 步骤 为什么需要序列化? 零拷贝 什么是零拷贝? 为什么需要零拷贝? 如何实现零拷贝? Netty 的零拷贝有何不同? 动态代理实现 HTTP/2 特性 ...

  9. 【Networking】gRPC golang 相关资料

    参考资料: Golang gRPC 示例:  http://www.cnblogs.com/YaoDD/p/5504881.html grpc golang学习心得(1)----安装与测试:   ht ...

随机推荐

  1. wpa_supplicant的移植

    解压,进入,使用默认配置文件 cd wpa_supplicant-2.6 cp defconfig .config 修改.config文件,修改部分,根据自己的需要进行这部分的配置 #指定libnl的 ...

  2. MyBatis的配置与使用(增,删,改,查)

    ---恢复内容开始--- Mybatis入门介绍 一.MyBatis介绍 什么是MyBtis? MyBatis 是一个简化和实现了 Java 数据持久化层(persistence layer)的开源框 ...

  3. redis数据类型--hash

    /** Redis应用之Hash数据类型* 问题1:操作命令* 问题2:存储实现原理和数据结构* 问题3:应用场景* */ 先了解下什么是hash,什么是hash碰撞:hash:是包含键值对的kv的数 ...

  4. APP Distribution Guide 苹果官网

    https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/AppDistributionGuide/Introduct ...

  5. Java修炼——基于TCP协议的Socket编程_双向通信_实现模拟用户登录

    首先我们需要客户端和服务器端. 服务器端需要:1.创建ServerSocket对象.2.监听客户端的请求数据.3.获取输入流(对象流)即用户在客户端所发过来的信息.                  ...

  6. [TimLinux] JavaScript 如何在html标签的data-*属性使用JSON数据

    1. HTML data-*属性 H5引入的data-*属性,可以在JavaScript通过.dataset.*的方式来获取属性的值,例如: /* HTML标签: * <input id=&qu ...

  7. Yii2框架那些折磨人的坑

    说点闲话 距离上次写博客,已经有一年了.在动手写之前,总是带着深深的罪恶感.被它折磨许久,终于,还是,动手了. 值得庆祝的一件事:最近开始健身了.每天动感单车45分钟,游泳45分钟,真的是(生)爽(不 ...

  8. CSS修饰文档

    定义字体类型 <html> <head> <meta http-equiv="Content-Type" content="text/htm ...

  9. 【玩转SpringBoot】配置文件yml的正确打开姿势

    序言 在很久以前,Spring的配置文件是基于XML的.它的名字就是applicationContext.xml,没错,就只有这一个xml文件. 它里面配置了所有的东西.但是数据库信息通常会单独拿出来 ...

  10. 搭建react native所遇到的坑

    一.所遇问题 在搭建react native环境中,遇到执行react native  run-android命令出现如下问题 Could not resolve all dependencies f ...