# package rpc

`import "net/rpc"`

rpc包提供了通过网络或其他I/O连接对一个对象的导出方法的访问。服务端注册一个对象，使它作为一个服务被暴露，服务的名字是该对象的类型名。注册之后，对象的导出方法就可以被远程访问。服务端可以注册多个不同类型的对象（服务），但注册具有相同类型的多个对象是错误的。

只有满足如下标准的方法才能用于远程访问，其余方法会被忽略：

    - 方法是导出的
    - 方法有两个参数，都是导出类型或内建类型
    - 方法的第二个参数是指针
    - 方法只有一个error接口类型的返回值

事实上，方法必须看起来像这样：

    func (t *T) MethodName(argType T1, replyType *T2) error

其中T、T1和T2都能被encoding/gob包序列化。这些限制即使使用不同的编解码器也适用。（未来，对定制的编解码器可能会使用较宽松一点的限制）

方法的第一个参数代表调用者提供的参数；第二个参数代表返回给调用者的参数。方法的返回值，如果非nil，将被作为字符串回传，在客户端看来就和errors.New创建的一样。如果返回了错误，回复的参数将不会被发送给客户端。

服务端可能会单个连接上调用ServeConn管理请求。更典型地，它会创建一个网络监听器然后调用Accept；或者，对于HTTP监听器，调用HandleHTTP和http.Serve。

想要使用服务的客户端会创建一个连接，然后用该连接调用NewClient。

更方便的函数Dial（DialHTTP）会在一个原始的连接（或HTTP连接）上依次执行这两个步骤。

生成的Client类型值有两个方法，Call和Go，它们的参数为要调用的服务和方法、一个包含参数的指针、一个用于接收接个的指针。

Call方法会等待远端调用完成，而Go方法异步的发送调用请求并使用返回的Call结构体类型的Done通道字段传递完成信号。

除非设置了显式的编解码器，本包默认使用encoding/gob包来传输数据。

这是一个简单的例子。一个服务端想要导出Arith类型的一个对象：

    package server
    type Args struct {
    	A, B int
    }
    type Quotient struct {
    	Quo, Rem int
    }
    type Arith int
    func (t *Arith) Multiply(args *Args, reply *int) error {
    	*reply = args.A * args.B
    	return nil
    }
    func (t *Arith) Divide(args *Args, quo *Quotient) error {
    	if args.B == 0 {
    		return errors.New("divide by zero")
    	}
    	quo.Quo = args.A / args.B
    	quo.Rem = args.A % args.B
    	return nil
    }

服务端会调用（用于HTTP服务）：

    arith := new(Arith)
    rpc.Register(arith)
    rpc.HandleHTTP()
    l, e := net.Listen("tcp", ":1234")
    if e != nil {
    	log.Fatal("listen error:", e)
    }
    go http.Serve(l, nil)

此时，客户端可看到服务"Arith"及它的方法"Arith.Multiply"、"Arith.Divide"。要调用方法，客户端首先呼叫服务端：

    client, err := rpc.DialHTTP("tcp", serverAddress + ":1234")
    if err != nil {
    	log.Fatal("dialing:", err)
    }

然后，客户端可以执行远程调用：

    // Synchronous call
    args := &server.Args{7,8}
    var reply int
    err = client.Call("Arith.Multiply", args, &reply)
    if err != nil {
    	log.Fatal("arith error:", err)
    }
    fmt.Printf("Arith: %d*%d=%d", args.A, args.B, reply)

或：

    // Asynchronous call
    quotient := new(Quotient)
    divCall := client.Go("Arith.Divide", args, quotient, nil)
    replyCall := <-divCall.Done	// will be equal to divCall
    // check errors, print, etc.

服务端的实现应为客户端提供简单、类型安全的包装。

## Constants

    const (
        // HandleHTTP使用的默认值
        DefaultRPCPath   = "/_goRPC_"
        DefaultDebugPath = "/debug/rpc"
    )

## Variables

    var DefaultServer = NewServer()

DefaultServer是*Server的默认实例，本包和Server方法同名的函数都是对其方法的封装。

    var ErrShutdown = errors.New("connection is shut down")

## type ServerError

    type ServerError string

ServerError represents an error that has been returned from the remote side of the RPC connection.

### func (ServerError) Error

    func (e ServerError) Error() string

## type Request

    type Request struct {
        ServiceMethod string // 格式："Service.Method"
        Seq           uint64 // 由客户端选择的序列号
        // 内含隐藏或非导出字段
    }

Request是每个RPC调用请求的头域。它是被内部使用的，这里的文档用于帮助debug，如分析网络拥堵时。

## type Response

    type Response struct {
        ServiceMethod string // 对应请求的同一字段
        Seq           uint64 // 对应请求的同一字段
        Error         string // 可能的错误
        // 内含隐藏或非导出字段
    }

Response是每个RPC调用回复的头域。它是被内部使用的，这里的文档用于帮助debug，如分析网络拥堵时。

## type ClientCodec

    type ClientCodec interface {
        // 本方法必须能安全的被多个go程同时使用
        WriteRequest(*Request, interface{}) error
        ReadResponseHeader(*Response) error
        ReadResponseBody(interface{}) error
        Close() error
    }

ClientCodec接口实现了RPC会话的客户端一侧RPC请求的写入和RPC回复的读取。客户端调用WriteRequest来写入请求到连接，然后成对调用ReadRsponseHeader和ReadResponseBody以读取回复。客户端在结束该连接的事务时调用Close方法。ReadResponseBody可以使用nil参数调用，以强制回复的主体被读取然后丢弃。

## type ServerCodec

    type ServerCodec interface {
        ReadRequestHeader(*Request) error
        ReadRequestBody(interface{}) error
        // 本方法必须能安全的被多个go程同时使用
        WriteResponse(*Response, interface{}) error
        Close() error
    }

ServerCodec接口实现了RPC会话的服务端一侧RPC请求的读取和RPC回复的写入。服务端通过成对调用方法ReadRequestHeader和ReadRequestBody从连接读取请求，然后调用WriteResponse来写入回复。服务端在结束该连接的事务时调用Close方法。ReadRequestBody可以使用nil参数调用，以强制请求的主体被读取然后丢弃。

## type Call

    type Call struct {
        ServiceMethod string      // 调用的服务和方法的名称
        Args          interface{} // 函数的参数（下层为结构体指针）
        Reply         interface{} // 函数的回复（下层为结构体指针）
        Error         error       // 在调用结束后，保管错误的状态
        Done          chan *Call  // 对其的接收操作会阻塞，直到远程调用结束
    }

Call类型代表一个执行中/执行完毕的RPC会话。

## type Client

    type Client struct {
        // 内含隐藏或非导出字段
    }

Client类型代表RPC客户端。同一个客户端可能有多个未返回的调用，也可能被多个go程同时使用。

### func NewClient

    func NewClient(conn io.ReadWriteCloser) *Client

NewClient返回一个新的Client，以管理对连接另一端的服务的请求。它添加缓冲到连接的写入侧，以便将回复的头域和有效负载作为一个单元发送。

### func NewClientWithCodec

    func NewClientWithCodec(codec ClientCodec) *Client

NewClientWithCodec类似NewClient，但使用指定的编解码器，以编码请求主体和解码回复主体。

### func Dial

    func Dial(network, address string) (*Client, error)

Dial在指定的网络和地址与RPC服务端连接。

### func DialHTTP

    func DialHTTP(network, address string) (*Client, error)

DialHTTP在指定的网络和地址与在默认HTTP RPC路径监听的HTTP RPC服务端连接。

### func DialHTTPPath

    func DialHTTPPath(network, address, path string) (*Client, error)

DialHTTPPath在指定的网络、地址和路径与HTTP RPC服务端连接。

### func (*Client) Call

    func (client *Client) Call(serviceMethod string, args interface{}, reply interface{}) error

Call调用指定的方法，等待调用返回，将结果写入reply，然后返回执行的错误状态。

### func (*Client) Go

    func (client *Client) Go(serviceMethod string, args interface{}, reply interface{}, done chan *Call) *Call

Go异步的调用函数。本方法Call结构体类型指针的返回值代表该次远程调用。通道类型的参数done会在本次调用完成时发出信号（通过返回本次Go方法的返回值）。如果done为nil，Go会申请一个新的通道（写入返回值的Done字段）；如果done非nil，done必须有缓冲，否则Go方法会故意崩溃。

### func (*Client) Close

    func (client *Client) Close() error

## type Server

    type Server struct {
        // 内含隐藏或非导出字段
    }

Server代表RPC服务端。

### func NewServer

    func NewServer() *Server

NewServer创建并返回一个*Server。

### func (*Server) Register

    func (server *Server) Register(rcvr interface{}) error

Register在server注册并公布rcvr的方法集中满足如下要求的方法：

    - 方法是导出的
    - 方法有两个参数，都是导出类型或内建类型
    - 方法的第二个参数是指针
    - 方法只有一个error接口类型的返回值

如果rcvr不是一个导出类型的值，或者该类型没有满足要求的方法，Register会返回错误。Register也会使用log包将错误写入日志。客户端可以使用格式为"Type.Method"的字符串访问这些方法，其中Type是rcvr的具体类型。

### func (*Server) RegisterName

    func (server *Server) RegisterName(name string, rcvr interface{}) error

RegisterName类似Register，但使用提供的name代替rcvr的具体类型名作为服务名。

### func (*Server) Accept

    func (server *Server) Accept(lis net.Listener)

Accept接收监听器l获取的连接，然后服务每一个连接。Accept会阻塞，调用者应另开线程："go server.Accept(l)"

### func (*Server) ServeConn

    func (server *Server) ServeConn(conn io.ReadWriteCloser)

ServeConn在单个连接上执行server。ServeConn会阻塞，服务该连接直到客户端挂起。调用者一般应另开线程调用本函数："go server.ServeConn(conn)"。ServeConn在该连接使用gob（参见encoding/gob包）有线格式。要使用其他的编解码器，可调用ServeCodec方法。

### func (*Server) ServeCodec

    func (server *Server) ServeCodec(codec ServerCodec)

ServeCodec类似ServeConn，但使用指定的编解码器，以编码请求主体和解码回复主体。

### func (*Server) ServeRequest

    func (server *Server) ServeRequest(codec ServerCodec) error

ServeRequest类似ServeCodec，但异步的服务单个请求。它不会在调用结束后关闭codec。

### func (*Server) ServeHTTP

    func (server *Server) ServeHTTP(w http.ResponseWriter, req *http.Request)

ServeHTTP实现了回应RPC请求的http.Handler接口。

### func (*Server) HandleHTTP

    func (server *Server) HandleHTTP(rpcPath, debugPath string)

HandleHTTP注册server的RPC信息HTTP处理器对应到rpcPath，注册server的debug信息HTTP处理器对应到debugPath。HandleHTTP会注册到http.DefaultServeMux。之后，仍需要调用http.Serve()，一般会另开线程："go http.Serve(l, nil)"

## func Register

    func Register(rcvr interface{}) error

Register在DefaultServer注册并公布rcvr的方法。

## func RegisterName

    func RegisterName(name string, rcvr interface{}) error

RegisterName函数类似Register函数，但使用提供的name代替rcvr的具体类型名作为服务名。

## func Accept

    func Accept(lis net.Listener)

Accept接收监听器l获取的连接，然后将每一个连接交给DefaultServer服务。Accept会阻塞，调用者应另开线程："go server.Accept(l)"

## func ServeConn

    func ServeConn(conn io.ReadWriteCloser)

ServeConn在单个连接上执行DefaultServer。ServeConn会阻塞，服务该连接直到客户端挂起。调用者一般应另开线程调用本函数："go ServeConn(conn)"。ServeConn在该连接使用gob（参见encoding/gob包）有线格式。要使用其他的编解码器，可调用ServeCodec方法。

## func ServeCodec

    func ServeCodec(codec ServerCodec)

ServeCodec类似ServeConn，但使用指定的编解码器，以编码请求主体和解码回复主体。

## func ServeRequest

    func ServeRequest(codec ServerCodec) error

ServeRequest类似ServeCodec，但异步的服务单个请求。它不会在调用结束后关闭codec。

## func HandleHTTP

    func HandleHTTP()

HandleHTTP函数注册DefaultServer的RPC信息HTTP处理器对应到DefaultRPCPath，和DefaultServer的debug处理器对应到DefaultDebugPath。HandleHTTP函数会注册到http.DefaultServeMux。之后，仍需要调用http.Serve()，一般会另开线程："go http.Serve(l, nil)"