Go语言的RPC包的路径为net/rpc,也就是放在了net包目录下面。因此我们可以猜测该RPC包是建立在net包基础之上的。在第一章“Hello, World”革命一节最后,我们基于http实现了一个打印例子。下面我们尝试基于rpc实现一个类似的例子。

1. 服务端:

  1. package main
  2. import (
  3. "net"
  4. "net/rpc"
  5. )
  6. type HelloService struct {}
  7. func (s *HelloService) Hello(request string, reply *string) error {
  8. *reply = "hello "+ request
  9. return nil
  10. }
  11. func main(){
  12. _ = rpc.RegisterName("HelloService", &HelloService{})
  13. listener, err := net.Listen("tcp", ":1234")
  14. if err != nil {
  15. panic("监听端口失败")
  16. }
  17. conn, err := listener.Accept()
  18. if err != nil {
  19. panic("建立链接失败")
  20. }
  21. rpc.ServeConn(conn)
  22. }

其中Hello方法必须满足Go语言的RPC规则:方法只能有两个可序列化的参数,其中第二个参数是指针类型,并且返回一个error类型,同时必须是公开的方法
然后就可以将HelloService类型的对象注册为一个RPC服务:(TCP RPC服务)。
其中rpc.Register函数调用会将对象类型中所有满足RPC规则的对象方法注册为RPC函数,所有注册的方法会放在“HelloService”服务空间之下。然后我们建立一个唯一的TCP链接,并且通过rpc.ServeConn函数在该TCP链接上为对方提供RPC服务。

2. 客户端

  1. func main() {
  2. client, err := rpc.Dial("tcp", "localhost:1234")
  3. if err != nil {
  4. log.Fatal("dialing:", err)
  5. }
  6. var reply string
  7. err = client.Call("HelloService.Hello", "hello", &reply)
  8. if err != nil {
  9. log.Fatal(err)
  10. }
  11. fmt.Println(reply)
  12. }

首先是通过rpc.Dial拨号RPC服务,然后通过client.Call调用具体的RPC方法。在调用client.Call时,第一个参数是用点号链接的RPC服务名字和方法名字,第二和第三个参数分别我们定义RPC方法的两个参数