RPC是远程过程调用的缩写(Remote Procedure Call),通俗地说就是调用远处的一个函数,是分布式系统中不同节点间流行的通信方式。Go语言的标准库提供了一个简单的RPC实现
server端
构造一个Cqh类型,其中的Test方法用于测试打印功能
注意:Test方法必须满足Go语言的RPC规则:
- 方法只能有两个可序列化的参数
- 其中第二个参数是指针类型,并且返回一个error类型,同时必须是公开的方法。
func (p *Cqh) Test(request string, reply *string) error { *reply = "test:" + request return nil }
服务端程序如下:
func main() { rpc.RegisterName("Cqh", new(Cqh)) listener, err := net.Listen("tcp", ":1234") if err != nil { log.Fatal("ListenTCP error", err) } for { conn, err := listener.Accept() if err != nil { log.Fatal("Accept error:", err) } rpc.ServeConn(conn) } }
其中rpc.Register函数调用会将对象类型中所有满足RPC规则的对象方法注册为RPC函数,所有注册的方法会放在“Cqh”服务空间之下。然后我们建立非阻塞的TCP链接,通过rpc.ServeConn函数在该TCP链接上为对方提供RPC服务。
client端
Go语言的RPC库最简单的使用方式是通过Client.Call方法进行同步阻塞调用,该方法的实现如下:
func (client *Client) Call(serviceMethod string, args interface{}, reply interface{}) error { call := <-client.Go(serviceMethod, args, reply, make(chan *Call, 1)).Done return call.Error }
首先通过Client.Go方法进行一次异步调用,返回一个表示这次调用的Call结构体。然后等待Call结构体的Done管道返回调用结果。
客户端程序如下:
package main import ( "net/rpc" "log" "fmt" ) func main() { client, err := rpc.Dial("tcp", ":1234") if err != nil { log.Fatal("dialing", err) } var reply string err = client.Call("Cqh.Test", "hello", &reply) if err != nil { log.Fatal(err) } fmt.Println(reply) }
rpc.Dial拨号RPC服务,然后通过client.Call调用具体的RPC方法。在调用client.Call时,第一个参数是用点号链接的RPC服务名字和方法名字,第二和第三个参数分别我们定义RPC方法的两个参数。
客户端运行后输出如下:
test:hello
由此以看出RPC的使用其实非常简单