• Go微服务框架2.Go语言RPC编程实践


    Go语言实现RPC编程

    上节课我们对RPC知识做了介绍,讲解了RPC的原理,通过图示方式讲解了RPC的内部执行过程。本节课,我们继续来学习RPC相关的内容。

    RPC官方库

    在Go语言官方网站的pkg说明中,提供了官方支持的rpc包,具体链接如下:https://golang.org/pkg/net/rpc/。官方提供的rpc包完整的包名是:net/rpc。根据官方的解释,rpc包主要是提供通过网络访问一个对象方法的功能。

    本节课,我们就来学习如何使用go语言官方提供的RPC包实现RPC调用编码。

    net/rpc库实现RPC调用编程

    前文我们已经讲过rpc调用有两个参与者,分别是:客户端(client)和服务器(server)

    首先是提供方法暴露的一方--服务器。

    一、服务定义及暴露

    在编程实现过程中,服务器端需要注册结构体对象,然后通过对象所属的方法暴露给调用者,从而提供服务,该方法称之为输出方法,此输出方法可以被远程调用。当然,在定义输出方法时,能够被远程调用的方法需要遵循一定的规则。我们通过代码进行讲解:

    func (t *T) MethodName(request T1,response *T2) error
    

    上述代码是go语言官方给出的对外暴露的服务方法的定义标准,其中包含了主要的几条规则,分别是:

    • 1、对外暴露的方法有且只能有两个参数,这个两个参数只能是输出类型或内建类型,两种类型中的一种。
    • 2、方法的第二个参数必须是指针类型。
    • 3、方法的返回类型为error。
    • 4、方法的类型是可输出的。
    • 5、方法本身也是可输出的。

    我们举例说明:假设目前我们有一个需求,给出一个float类型变量,作为圆形的半径,要求通过RPC调用,返回对应的圆形面积。具体的编程实现思路如下:

    type MathUtil struct{
    }
    //该方法向外暴露:提供计算圆形面积的服务
    func (mu *MathUtil) CalculateCircleArea(req float32, resp *float32) error {
    	*resp = math.Pi * req * req //圆形的面积 s = π * r * r
    	return nil //返回类型
    }
    

    在上述的案例中,我们可以看到:

    • 1、Calculate方法是服务对象MathUtil向外提供的服务方法,该方法用于接收传入的圆形半径数据,计算圆形面积并返回。
    • 2、第一个参数req代表的是调用者(client)传递提供的参数。
    • 3、第二个参数resp代表要返回给调用者的计算结果,必须是指针类型。
    • 4、正常情况下,方法的返回值为是error,为nil。如果遇到异常或特殊情况,则error将作为一个字符串返回给调用者,此时,resp参数就不会再返回给调用者。

    至此为止,已经实现了服务端的功能定义,接下来就是让服务代码生效,需要将服务进行注册,并启动请求处理。

    二、注册服务及监听请求

    net/rpc包为我们提供了注册服务和处理请求的一系列方法,结合本案例实现注册及处理逻辑,如下所示:

    //1、初始化指针数据类型
    mathUtil := new(MathUtil) //初始化指针数据类型
    
    //2、调用net/rpc包的功能将服务对象进行注册
    err := rpc.Register(mathUtil)
    if err != nil {
    	panic(err.Error())
    }
    
    //3、通过该函数把mathUtil中提供的服务注册到HTTP协议上,方便调用者可以利用http的方式进行数据传递
    rpc.HandleHTTP()
    
    //4、在特定的端口进行监听
    listen, err := net.Listen("tcp", ":8081")
    if err != nil {
    	panic(err.Error())
    }
    go http.Serve(listen, nil)
    

    经过服务注册和监听处理,RPC调用过程中的服务端实现就已经完成了。接下来需要实现的是客户端请求代码的实现。

    三、客户端调用

    在服务端是通过Http的端口监听方式等待连接的,因此在客户端就需要通过http连接,首先与服务端实现连接。

    • 客户端连接服务端

      client, err := rpc.DialHTTP("tcp", "localhost:8081")
      if err != nil {
      	panic(err.Error())
      }
      
    • 远端方法调用
      客户端成功连接服务端以后,就可以通过方法调用调用服务端的方法,具体调用方法如下:

      var req float32 //请求值
      req = 3
      
      var resp *float32 //返回值
      err = client.Call("MathUtil.CalculateCircleArea", req, &resp)
      if err != nil {
      panic(err.Error())
      }
      fmt.Println(*resp)
      

      上述的调用方法核心在于client.Call方法的调用,该方法有三个参数,第一个参数表示要调用的远端服务的方法名,第二个参数是调用时要传入的参数,第三个参数是调用要接收的返回值。
      上述的Call方法调用实现的方式是同步的调用,除此之外,还有一种异步的方式可以实现调用。异步调用代码实现如下:

      var respSync *float32
      //异步的调用方式
      syncCall := client.Go("MathUtil.CalculateCircleArea", req, &respSync, nil)
      replayDone := <-syncCall.Done
      fmt.Println(replayDone)
      fmt.Println(*respSync)
      
    多参数的请求调用参数传递

    上述内容演示了单个参数下的RPC调用,对于多参数下的请求该如何实现。我们通过另外一个案例进行演示。

    假设现在需要实现另外一个需求:通过RPC调用实现计算两个数字相加功能并返回计算结果。此时,就需要传递两个参数,具体实现如下:

    将参数定义在一个新的结构体中,存放在param包中:

    type AddParma struct {
    	Args1 float32 //第一个参数
    	Args2 float32 //第二个参数
    }
    

    在server.go文件中,实现两数相加的功能,并实现服务注册的逻辑:

    func (mu *MathUtil) Add(param param.AddParma, resp *float32) error {
    	*resp = param.Args1 + param.Args2 //实现两数相加的功能
            return nil
    }
    mathUtil := new(MathUtil)
    
    err := rpc.RegisterName("MathUtil", mathUtil)
    if err != nil {
    	panic(err.Error())
    }
    
    rpc.HandleHTTP()
    
    listen, err := net.Listen("tcp", ":8082")
    http.Serve(listen, nil)
    

    在本案例中,我们通过新的注册方法rpc.RegisterName实现了服务的注册和调用。

    至此,我们已经完成了net/rpc包的最基础的使用。

  • 相关阅读:
    为图片指定区域添加链接
    数值取值范围问题
    【leetcode】柱状图中最大的矩形(第二遍)
    【leetcode 33】搜索旋转排序数组(第二遍)
    【Educational Codeforces Round 81 (Rated for Div. 2) C】Obtain The String
    【Educational Codeforces Round 81 (Rated for Div. 2) B】Infinite Prefixes
    【Educational Codeforces Round 81 (Rated for Div. 2) A】Display The Number
    【Codeforces 716B】Complete the Word
    一个简陋的留言板
    HTML,CSS,JavaScript,AJAX,JSP,Servlet,JDBC,Structs,Spring,Hibernate,Xml等概念
  • 原文地址:https://www.cnblogs.com/wydxry/p/15854353.html
Copyright © 2020-2023  润新知