Skip to content

Latest commit

 

History

History
162 lines (142 loc) · 4.43 KB

rpc.md

File metadata and controls

162 lines (142 loc) · 4.43 KB

rpc

Go语言的net/rpc包实现了最基本的RPC调用,它默认通过HTTP协议传输gob数据实现远程调用。 服务端收到客户端请求后,会反序列化客户端传来的gob数据,获取要调用的方法名称,并通过反射来 调用服务端对外提供的方法,这个方法具有两个参数一个返回值,两个参数分别为客户端的请求内容以及服务端要返回的 数据体指针; 返回值则是一个error对象。下面对RPC服务的构建,以及RPC客户端同步和异步调用方式进行代码举例说明。

  • 服务器端
相关包"log"
"net"
"net/rpc"
"net/rpc/jsonrpc"
相关函数func NewServer() *Server
func (server *Server) Register(rcvr interface{}) error
func (server *Server) ServeCodec(codec ServerCodec)
func NewServerCodec(conn io.ReadWriteCloser) rpc.ServerCodec
举例import (
    "log"
    "net"
    "net/rpc"
    "net/rpc/jsonrpc"
)

//定义一个server端的rpc处理器
type ServerHandler struct {}


//RpcObj 数据通信用的结构体
type RpcObj struct {
	Id   int `json:"id"`
	Name string `json:"name"`
}

//定义server端对外提供的rpc方法
func (serverHandler ServerHandler) GetName(id int, returnObj *RpcObj) error {
    log.Println("server\t-", "recive GetName call, id:", id)
    returnObj.Id = id
    returnObj.Name = "gopher"
    return nil
}

func startRPCServer() {
    server := rpc.NewServer()
    serverHandler := new(ServerHandler)
    server.Register(serverHandler)

    l, e := net.Listen("tcp4",":8888")
    if e != nil {
        log.Fatal("listen error:", e)
    }
    defer l.Close()

    for {
        conn, err := l.Accept()
        if err != nil {
            log.Println("Accept error:", err)
            continue
        }
        go server.ServeCodec(jsonrpc.NewServerCodec(conn))
    }
}
func init() {
    log.SetFlags(log.LstdFlags|log.Llongfile)
}

func main() {
    startRPCServer()
}
说明1. rpc处理器ServerHandler不需要任何字段只要符合net/rpc server端约定的方法即可该约定
    的方法必须具有两个参数和一个error类型的返回值
2. 定义数据通信用的结构体RpcObj
3. 定义服务端对外提供的方法调用GetName
4. 定义RPC服务startRPCServer
    4.1 定义rpc服务对象server
    4.2 应用Register函数注册rpc处理器
    4.5 启动服务监听本地端口号进入等待客户端连接的阻塞状态
  • 客户端
相关包"log"
"net"
"time"
"net/rpc/jsonrpc"
相关函数func DialTimeout(network, address string, timeout time.Duration) (Conn, error)
func NewClient(conn io.ReadWriteCloser) *rpc.Client
func (client *Client) Call(serviceMethod string, args interface{}, reply interface{}) error
func (client *Client) Go(serviceMethod string, args interface{}, reply interface{}, done chan *Call) *Call
举例import (
	"log"
	"time"
	"net"
	"net/rpc/jsonrpc"
)

type RpcObj struct {
	Id   int `json:"id"`
	Name string `json:"name"`
}
//同步调用方法
func callRpcBySynchronous() {
	client, err := net.DialTimeout("tcp", "localhost:8888", time.Second * 30) // 30秒超时时间
	if err != nil {
		log.Fatal("client\t-", err.Error())
	}
	defer client.Close()

	clientRpc := jsonrpc.NewClient(client)
	var rpcObj RpcObj
	log.Println("client\t:", "call GetName method")
	clientRpc.Call("ServerHandler.GetName", 1, &rpcObj)
	log.Println("client\t:", "recive remote return", rpcObj)
}

//异步调用方法
func callRpcByASynchronous() {
    client, err := net.DialTimeout("tcp", "localhost:8888", time.Second*30) // 30秒超时时间
    if err != nil {
        log.Fatal("client\t-", err.Error())

    }   
    defer client.Close()

    clientRpc := jsonrpc.NewClient(client)
    var wg sync.WaitGroup
    for i:= 0;i<10; i++{
        divCall := clientRpc.Go("ServerHandler.GetName", i, &RpcObj{}, nil)
        wg.Add(1)
        go func(num int) {
            defer wg.Done()
            replyCall := <-divCall.Done
            log.Println("client\t-", "recive remote return", replyCall.Reply)
        }(i)
    }   
    wg.Wait()
}

func init() {
	log.SetFlags(log.LstdFlags|log.Llongfile)
}

func main() {
	callRpcBySynchronous()
    callRpcByASynchronous()
}
说明1. 应用net.DialTimeout()函数与server端建立网络连接,并设置关闭
2. 定义数据通信用的结构体RpcObj与server端定义相同
3. 应用jsonrpc.NewClient建立rpc通信通道
4. 应用clientRpc.Call调用server端对外提供的方法
5. 应用clientRpc.Go调用server端对外提供的方法