Go语言的标准库提供了 RPC 框架和不同的 RPC 实现。
什么是 RPC远程过程调用(Remote Procedure Call,简称 RPC)是一个计算机通信协议。该协议允许运行于一台计算机的程序调用另一台计算机的子程序,而开发人员无需额外地为这个交互作用编程。如果涉及的软件采用面向对象编程,那么远程过程调用亦可称作远程调用或远程方法调用。
通俗的来讲就是,RPC 允许跨机器、跨语言调用计算机程序。例如我们用Go语言写了一个获取用户信息的方法 getUserInfo,并把Go语言程序部署在阿里云服务器上面,另外我们还有一个部署在腾讯云上面的 PHP 项目,需要调用Go语言的 getUserInfo 方法获取用户信息,PHP 跨机器调用 Go 方法的过程就是 RPC 调用。
RPC 的工作流程如下图所示:
图:远程过程调用流程图
流程说明如下:(1) 调用客户端句柄,执行传送参数;(2) 调用本地系统内核发送网络消息;(3) 消息传送到远程主机;(4) 服务器句柄得到消息并取得参数;(5) 执行远程过程;(6) 执行的过程将结果返回服务器句柄;(7) 服务器句柄返回结果,调用远程系统内核;(8) 消息传回本地主机;(9) 客户句柄由内核接收消息;(10) 客户接收句柄返回的数据。Go语言中如何实现 RPC 的在Go语言中实现 RPC 非常简单,有封装好的官方包和一些第三方包提供支持。Go语言中 RPC 可以利用 tcp 或 http 来传递数据,可以对要传递的数据使用多种类型的编解码方式。
Go语言的 net/rpc 包使用 enCoding/gob 进行编解码,支持 tcp 或 http 数据传输方式,由于其他语言不支持 gob 编解码方式,所以使用 net/rpc 包实现的 RPC 方法没办法进行跨语言调用。
此外,Go语言还提供了 net/rpc/Jsonrpc 包实现 RPC 方法,JsON RPC 采用 JsON 进行数据编解码,因而支持跨语言调用。但目前的 Jsonrpc 包是基于 tcp 协议实现的,暂时不支持使用 http 进行数据传输。
除了Go语言官方提供的 rpc 包,还有许多第三方包为在Go语言中实现 RPC 提供支持,大部分第三方 rpc 包的实现都是使用 protobuf 进行数据编解码,根据 protobuf 声明文件自动生成 rpc 方法定义与服务注册代码,所以在Go语言中可以很方便的进行 rpc 服务调用。net/rpc 包rpc 包提供了通过网络或其他 I/O 连接对一个对象的导出方法的访问。服务端注册一个对象,使它作为一个服务被暴露,服务的名字是该对象的类型名。注册之后,对象的导出方法就可以被远程访问。服务端可以注册多个不同类型的对象(服务),但注册具有相同类型的多个对象是错误的。
只有满足如下标准的方法才能用于远程访问,其余方法会被忽略:
方法是可导出的;方法有两个参数,都是导出类型或内建类型;方法的第二个参数是指针类型;方法只有一个 error 接口类型的返回值。
下面的示例演示了Go语言 net/rpc 包实现 RPC 方法,使用 http 作为 RPC 的载体,通过 net/http 包监听客户端连接请求。
服务端代码如下:
package mainimport ( "errors" "fmt" "log" "net" "net/http" "net/rpc" "os")// 算数运算结构体type Arith struct {}// 算数运算请求结构体type ArithRequest struct { A int B int}// 算数运算响应结构体type ArithResponse struct { Pro int // 乘积 Quo int // 商 Rem int // 余数}// 乘法运算方法func (this *Arith) Multiply(req ArithRequest,res *ArithResponse) error { res.Pro = req.A * req.B return nil}// 除法运算方法func (this *Arith) divIDe(req ArithRequest,res *ArithResponse) error { if req.B == 0 { return errors.New("除以零") } res.Quo = req.A / req.B res.Rem = req.A % req.B return nil}func main() { rpc.Register(new(Arith)) // 注册rpc服务 rpc.Handlehttp() // 采用http协议作为rpc载体 lis,err := net.Listen("tcp","127.0.0.1:8080") if err != nil { log.Fatalln("致命错误: ",err) } fmt.Fprintf(os.Stdout,"%s","开始连接") http.Serve(lis,nil)}服务端程序运行之后将会监听本地的 8080 端口,下面我们再来看一下客户端程序,用于连接服务端并实现 RPC 方法调用,完整代码如下:
package mainimport ( "fmt" "log" "net/rpc")// 算数运算请求结构体type ArithRequest struct { A int B int}// 算数运算响应结构体type ArithResponse struct { Pro int // 乘积 Quo int // 商 Rem int // 余数}func main() { conn,err := rpc.Dialhttp("tcp","127.0.0.1:8080") if err != nil { log.Fatalln("连接错误: ",err) } req := ArithRequest{11,2} var res ArithResponse err = conn.Call("Arith.Multiply",req,&res) // 乘法运算 if err != nil { log.Fatalln("算术误差: ",err) } fmt.Printf("%d * %d = %d\n",req.A,req.B,res.Pro) err = conn.Call("Arith.divIDe",&res) if err != nil { log.Fatalln("算术误差: ",err) } fmt.Printf("%d / %d,商是 %d,余数是 %d\n",res.Quo,res.Rem)}运行结果如下:
11 * 2 = 22
11 / 2,商是 5,余数是 1
Go语言提供了 net/rpc/Jsonrpc 包,用于提供基于 Json 编码的 RPC 支持。在不指定编码协议时,默认采用 Go 特有的 gob 编码协议。但是其他语言一般不支持 Go 的 gob 协议,所以如果需要跨语言的 RPC 调用,需要采用通用的编码协议。
服务端部分的代码如下所示:
package mainimport ( "errors" "fmt" "log" "net" "net/rpc" "net/rpc/Jsonrpc" "os")// 算数运算结构体type Arith struct {}// 算数运算请求结构体type ArithRequest struct { A int B int}// 算数运算响应结构体type ArithResponse struct { Pro int // 乘积 Quo int // 商 Rem int // 余数}// 乘法运算方法func (this *Arith) Multiply(req ArithRequest,res *ArithResponse) error { if req.B == 0 { return errors.New("除以零") } res.Quo = req.A / req.B res.Rem = req.A % req.B return nil}func main() { rpc.Register(new(Arith)) // 注册rpc服务 lis,"开始连接") for { conn,err := lis.Accept() // 接收客户端连接请求 if err != nil { continue } go func(conn net.Conn) { // 并发处理客户端请求 fmt.Fprintf(os.Stdout,"新连接接入\n") Jsonrpc.ServeConn(conn) }(conn) }}上述服务端程序启动后,将会监听本地的 8080 端口,并处理客户端的 tcp 连接请求。下面我们再来实现一个客户端程序来连接上述服务端并进行 RPC 调用,完整代码如下:
package mainimport ( "fmt" "log" "net/rpc/Jsonrpc")// 算数运算请求结构体type ArithRequest struct { A int B int}// 算数运算响应结构体type ArithResponse struct { Pro int // 乘积 Quo int // 商 Rem int // 余数}func main() { conn,err := Jsonrpc.Dial("tcp",3} var res ArithResponse err = conn.Call("Arith.Multiply",res.Rem)}运行结果如下:
11 * 3 = 33
11 / 3,商是 3,余数是 2
以上是内存溢出为你收集整理的Go语言RPC协议:远程过程调用全部内容,希望文章能够帮你解决Go语言RPC协议:远程过程调用所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)