Golang实现RPC通信
在Go语言中实现RPC(Remote Procedure Call)相对简单,因为Go标准库中已经包含了net/rpc包,它提供了创建RPC服务的基础设施。下面是一个简单的RPC服务和客户端的例子
服务端
首先,定义一个服务对象,方法是首字母大写的方法。这些方法需要有两个参数,第一个是接收参数,第二个是返回给客户端的结果参数,此外还需要一个返回值error。
package main
import (
"fmt"
"net/http"
"net/rpc"
)
type Rect struct {
}
type Params struct {
Height int
Width int
}
func (r *Rect) Area(p Params, ret *int) error {
*ret = p.Width * p.Height
return nil
}
func main() {
rect := new(Rect)
// 注册RPC服务
rpc.Register(rect)
rpc.HandleHTTP()
// 监听TCP端口
err := http.ListenAndServe(":8889", nil)
if err != nil {
fmt.Println("err:", err)
}
}
客户端
客户端需要使用rpc.Dial来连接RPC服务端,并调用Call方法来执行远程方法。
package main
import (
"fmt"
rpc2 "net/rpc"
)
type Params struct {
Height int
Width int
}
func main() {
rp, err := rpc2.DialHTTP("tcp", "127.0.0.1:8889")
if err != nil {
fmt.Println("error1", err)
}
ret := 0
err = rp.Call("Rect.Area", Params{100, 20}, &ret)
if err != nil {
fmt.Println("error", err)
}
fmt.Println("area", ret)
}
调用过程
- 客户端调用本地的RPC代理存根(stub),就像调用本地函数一样
- 存根将调用的方法和传递的参数打包成一种网络可传输的形式(消息),这个过程称为序列化或编组(marshalling)
- 客户端通过网络将这个打包好的请求信息发送给服务端
- 服务端的监听器接收到请求,将请求数据传递给服务端的RPC代理存根。
- 服务端的存根解包(反序列化或解编组)请求信息,获取方法名和参数。(unmarshalling)。
- 服务端存根根据解包得到的信息,调用本地的服务程序。
- 服务执行完毕后,服务端存根将结果打包成网络可传输的形式。
- 服务端将打包后的执行结果通过网络发送回客户端。
- 客户端的RPC代理存根接收到响应信息。
- 客户端存根解包响应信息,获取执行结果。
- 客户端存根将解包后的结果返回给客户端程序,就像本地调用的返回结果一样。