Overview
type Args struct {A, B int}type Quotient struct {Quo, Rem int}type Arith intfunc (t *Arith) Multiply(args *Args, reply *int) error {*reply = args.A * args.Breturn 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.Bquo.Rem = args.A % args.Breturn nil}func main() {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)}
golang 实现的 RPC 是基于 HTTP 的,RPC Server 实际上就是一个 Http Server,通过将 Service 注册到 Server 上,就可以通过 Clinet 调用 service 上的函数。
图一:overview
Server
rpc 对 http 的侵入是根据 http 的 Hijacker 实现的,ResponseWriter 实现了 Hijack 方法,能够从中获取到 conn,通过 conn 生成 Encoder 和 Decoder。
为什么 Encoder 需要从 buf 上生成,而 Decoder 直接从 conn 上就可以?

图二: ServeHTTP
Server 通过两层 map 能够找对对应 Service 对应的方法,这里大量使用了反射的方法。
图三:Register
Client

图四:Call
对于每一个 Request,会生成一个 seq 作为 key,将其存储到 map 中。接收到 Response 后会根据里面存储的 seq 确定哪一个是对应的 Call。
这里有两种方式发起 RPC 调用,Go 是异步的,Call 是同步的,通过监听 Call 的 done channel,一直阻塞到 Response 返回。
func (client *Client) Go(serviceMethod string, args interface{}, reply interface{}, done chan *Call) *Call {// ...return call}func (client *Client) Call(serviceMethod string, args interface{}, reply interface{}) error {call := <-client.Go(serviceMethod, args, reply, make(chan *Call, 1)).Donereturn call.Error}
