Go语言RPC协议:远程过程调用
发布时间:2020-12-16 09:36:18 所属栏目:大数据 来源:网络整理
导读:RPC 协议构建于 TCP、UDP 或者是 HTTP 之上,允许开发人员直接调用另一台计算机上的程序,而开发人员无需额外地为这个调用过程编写网络通信相关代码,使得开发网络分布式类型的应用程序更加容易。 Go语言的标准库提供了 RPC 框架和不同的 RPC 实现。 什么是 R
RPC 协议构建于 TCP、UDP 或者是 HTTP 之上,允许开发人员直接调用另一台计算机上的程序,而开发人员无需额外地为这个调用过程编写网络通信相关代码,使得开发网络分布式类型的应用程序更加容易。 Go语言的标准库提供了 RPC 框架和不同的 RPC 实现。 什么是 RPC远程过程调用(Remote Procedure Call,简称 RPC)是一个计算机通信协议。该协议允许运行于一台计算机的程序调用另一台计算机的子程序,而开发人员无需额外地为这个交互作用编程。如果涉及的软件采用面向对象编程,那么远程过程调用亦可称作远程调用或远程方法调用。通俗的来讲就是,RPC 允许跨机器、跨语言调用计算机程序。例如我们用Go语言写了一个获取用户信息的方法 getUserInfo,并把Go语言程序部署在阿里云服务器上面,另外我们还有一个部署在腾讯云上面的 php 项目,需要调用Go语言的 getUserInfo 方法获取用户信息,php 跨机器调用 Go 方法的过程就是 RPC 调用。 RPC 的工作流程如下图所示: 图:远程过程调用流程图 流程说明如下:
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 连接对一个对象的导出方法的访问。服务端注册一个对象,使它作为一个服务被暴露,服务的名字是该对象的类型名。注册之后,对象的导出方法就可以被远程访问。服务端可以注册多个不同类型的对象(服务),但注册具有相同类型的多个对象是错误的。只有满足如下标准的方法才能用于远程访问,其余方法会被忽略:
下面的示例演示了Go语言 net/rpc 包实现 RPC 方法,使用 http 作为 RPC 的载体,通过 net/http 包监听客户端连接请求。 服务端代码如下: package main import ( "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 main import ( "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 = %dn",req.A,req.B,res.Pro) err = conn.Call("Arith.Divide",&res) if err != nil { log.Fatalln("算术误差: ",err) } fmt.Printf("%d / %d,商是 %d,余数是 %dn",res.Quo,res.Rem) }运行结果如下:
11 * 2 = 22 net/rpc/jsonrpc 库上面的例子演示了使用 net/rpc 包实现 RPC 的过程,但是没办法在其他语言中调用上面例子所实现的 RPC 方法。Go语言提供了 net/rpc/jsonrpc 包,用于提供基于 json 编码的 RPC 支持。在不指定编码协议时,默认采用 Go 特有的 gob 编码协议。但是其他语言一般不支持 Go 的 gob 协议,所以如果需要跨语言的 RPC 调用,需要采用通用的编码协议。 服务端部分的代码如下所示: package main import ( "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 main import ( "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 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |