1、RPC使用的步骤

——-服务端:
1、注册rpc服务对象,给对象绑定方法(1.定义类,2.绑定类方法)

  1. rpc.RegisterName("服务名",回调对象)

2、创建监听器

listener,err := net.Listen()

3、建立连接

conn,err := listener.Accept()

4、将连接绑定rpc服务

rpc.ServerConn(conn)

——-客户端:
1、用rpc连接服务器。rpc.Dial()

conn,err := rpc.Dial()

2、调用远程函数。

conn.Call("服务名.方法名",传入参数,传出参数)

二、RPC相关函数

1、注册rpc服务

func (server *Server) RegisterName(name string, rcvr interface{}) error
    参数1:服务名。字符串类型。
    参数2:对应 rpc 对象。该对象绑定方法要满足如下条件:
        1)方法必须是导出的 -- 包外可见。
        2)方法必须有两个参数,都是导出类型、内建类型。
        3)方法的第二个参数必须是 “指针”  (传出参数)
        4)方法只有一个 error 接口类型的 

举例:
type World stuct{
}
如:func (this *world) Helloword(name string,resp *string) error{
}
rpc.RegisterName("服务名",new(World))

2、绑定rpc服务

func (server *Server) ServeConn(conn io.ReadWriteCloser)
    conn:成功建立好连接的 socket -- conn

3、调用远程函数

func (client *Client) Call(serviceMethod string, args interface{}, reply interface{}) error
    serviceMethod:服务名.方法名
    args:传入参数。方法需要的数据
    reply:传出参数。定义 var 变量,&变量名 完成参数。

4、小案例

1.服务端

package main

import (
    "fmt"
    "net"
    "net/rpc"
)

// World 定义类对象
type World struct {
}

// HelloWorld 绑定类方法,方法名为HelloWorld
func (this *World) HelloWorld(name string, resp *string) error {
    *resp = name + "您好!"
    return nil
}

func main() {
    //1.注册rpc服务,绑定方法,服务名为hello
    err:=rpc.RegisterName("hello",new(World))
    if err!=nil{
        fmt.Println("注册rpc服务失败!,",err)
        return
    }
    //2.设置监听
    listener,err:=net.Listen("tcp","127.0.0.1:8800")
    if err!=nil{
        fmt.Println("net.Listen err:",err)
        return
    }
    defer listener.Close()
    fmt.Println("开始监听 ...")
    //3.建立连接
    conn,err:=listener.Accept()
    if err!=nil{
        fmt.Println("listener.Accept err:",err)
        return
    }
    defer conn.Close()
    fmt.Println("连接成功 ...")
    //4.绑定服务
    rpc.ServeConn(conn)
}

2.客户端

package main

import (
    "fmt"
    "net/rpc"
)

func main() {
    //1.rpc连接服务器 --Dial()
    conn, err := rpc.Dial("tcp", "127.0.0.1:8800")
    if err != nil {
        fmt.Println("rpc.Dial err:,", err)
        return
    }
    defer conn.Close()
    //2.调用远程函数
    var reply string //接受函数返回值 --- 传出参数
    err = conn.Call("hello.HelloWorld", "李白", &reply)
    if err != nil {
        fmt.Println("Call err:,", err)
        return
    }
    fmt.Println(reply)
}

三、json版rpc

  • 使用 nc -l 127.0.0.1 8800 充当服务器
  • 02-client.go 充当客户端。发起通信 —- 产生乱码
    • 因为:RPC使用了go语言特有的数据序列化gob。其他编程语言不能解析
  • 使用通用的 序列化、反序列化。 —- json、protobuf

修改客户端,使用jsonrpc:

conn, err := jsonrpc.Dial("rcp","127.0.0.1:8800")

使用 nc -l 127.0.0.1 8800 充当服务器
看到结果:

{"method":"hello.HelloWorld","params":["李白"],"id":0}