下面首先会进行一个简单的RPC介绍,然后通过一个简易计算器的例子来了解如何运用GO标准库RPC。
1 RPC简介
RPC即远程过程调用(Remote Procedure Call),是一种通信协议,该协议允许运行于一台计算机的程序调用另一台计算机的程序,而程序员无需额外地为这个交互编程。 一个典型的RPC模型如下图所示,左边为消费者(客户端),右边为提供者(服务端),客户端通过RPC框架可直接调用服务端函数。
在本文中,主要运用GO语言标准库中自带的net/rpc
库。其rpc实现使用encoding/gob进行编解码,支持tcp和http数据传输方式,但由于大部分语言不支持gob编码,所以此RPC实现方法仅支持使用Golang语言编写的客户机与服务器。GO语言标准库还实现了net/rpc/jsonrpc
库,采用JSON进行编解码,因此支持跨语言调用。接下来将会通过一个经典的计算器例子来说明GO标准库net/rpc
使用方法。
2 RPC实现简易计算机
RPC的实现主要分为服务端实现以及客户端实现。
服务端实现主要分为三步:
- 定义输入输出参数
- 实现拟调用的方法
- 注册服务
代码及说明如下:
package main
import (
"errors"
"log"
"net/http"
"net/rpc"
)
// CalRequest 定义请求体,计算函数接受A、B值,并根据C来进行计算操作
// 注意:此处所有首字母都要大写,因为要供其他包进行调用。
type CalRequest struct {
A int
B int
C string
}
// CalReply 定义响应体,返回结果。
// 注意:此处所有首字母都要大写,因为要供其他包进行调用。
type CalReply struct {
Result int
}
// CalService 定义服务端
type CalService struct {
}
// Cal 定义相加函数供客户端调用。
//注意:1.此方法名首字母也要大写。
//2.此函数需为服务端结构体CalService的方法。
//3.函数参数有且仅有两个,第一个参数为输入参数,第二个参数为返回参数。
//4.函数返回值有且仅有一个,为error类型
func (s *CalService) Cal(request *CalRequest,reply *CalReply)error{
switch request.C {
case "+":
reply.Result=request.A+request.B
case "-":
reply.Result=request.A-request.B
case "/":
reply.Result=request.A/request.B
case "*":
reply.Result=request.A*request.B
default:
return errors.New("C is not the correct value. ")
}
return nil
}
//注册服务
func main(){
//注册一个rpc服务
service:=&CalService{}
rpc.Register(service)
//绑定http协议。此时RPC使用HTTP协议进行服务端和客户端的通信。
//实际上,当客户端发起一个 RPC 调用时,本质上是将要调用的方法和参数包装成一个 HTTP 请求。
//服务端收到 HTTP 请求后,解码出要调用的本地方法名称和入参,然后调用本地方法。
//在本地方法调用完成后再将结果写入到 HTTP 响应中,客户端收到响应后,再解析出远程调用的结果。
rpc.HandleHTTP()
//进行监听。
err:=http.ListenAndServe(":8000",nil)
if err != nil {
log.Panicln(err)
}
}
客户端实现主要分为两步:
- 连接服务
- 调用
代码及说明如下:
package main
import (
"fmt"
"log"
"net/rpc"
)
// CalRequest 定义请求体,计算函数接受A、B值,并根据C来进行计算操作
// 注意:此处结构体名可与服务端名不同,但其内的元素名字应该与服务端完全一致,不然会出现调用错误。
type CalRequest struct {
A int
B int
C string
}
// CalReply 定义响应体,返回结果。
// 注意:此处结构体名可与服务端名不同,但其内的元素名字应该与服务端完全一致,不然会出现调用错误。
type CalReply struct {
Result int
}
func main() {
//连接远程RPC服务器
conn,err:=rpc.DialHTTP("tcp",":8000")
if err != nil {
log.Fatal(err)
}
defer conn.Close()
//调用方法
reply:=&CalReply{}
err=conn.Call("CalService.Cal",&CalRequest{1,2,"+"},reply)
if err != nil {
log.Fatal(err)
}
fmt.Println(reply.Result)
}
3 总结
至此,基于RPC的简易计算机实现完毕。客户端可以通过调用RPC来使用服务端提供的简单计算接口。
GO标准库提供的RPC功能还比较单薄,现有很多其他很经典的RPC框架,如grpc、dubbo、motan等。其提供的功能更加的多样化,比如协议交换(protocol exchange)、注册中心(registry)、服务发现(service discovery)、负载均衡(load balance)、超时处理(timeout processing)等等,面对不同的应用场景应该合理的选用不同的RPC框架。