【GOLANG】第一章 RPC 源码分析

来源:互联网 发布:xshell mac 代替 编辑:程序博客网 时间:2024/05/23 10:18

第一章 RPC golang源码分析

 

rpc服务器也就是在tcp服务器的基础上加上自定义的rpc协议而已。一个rpc协议里,主要有个3个非常重要的信息。

· 调用的远程method名字,一般就是一个函数名

· call参数,也就是发送给服务器的数据

· 客户端生成的调用请求seq

 

1.1 官方例子

首先看看官方给出的使用例子:看看rpc.Register到底做了什么事情!

type Args struct {
       A, B int
}

func (t *Arith) Multiply(args *Args, reply *int) error {
       *reply = args.A * args.B
       return nil
}

 

arith := new(Arith)
rpc.Register(arith)

找到regsiter主要函数如下所示:主要是把结构体加入到Server结构体中serverMap中, 初始化工作,赋值方法等操作。

func (server *Serverregister(rcvr interface{}name stringuseName boolerror {
       s := new(service)
  。。。。。。。。。。。。。。。。
       server.serviceMap[s.name] = s
       return nil
}

那么rpc服务器如何能够根据method去调用对应的方法呢?Go语言在这里其实采用反射的手段,虽然表面上是注册的对象,实际却是通过反射取得了对象的所有方法,然后采用了map表保存了method到方法的映射

 

 

1.2 结构体

 

type Server struct {
       mu         sync.RWMutex // protects the serviceMap
       serviceMap map[string]*service
       reqLock    sync.Mutex // protects freeReq
       freeReq    *Request
       respLock   sync.Mutex // protects freeResp
       freeResp   *Response
}

 

rpc的service包括方法名、方法反射,类型等

type service struct {
       name   string                 // name of service
       rcvr   reflect.Value          // receiver of methods for the service
       typ    reflect.Type           // type of the receiver
       method map[string]*methodType // registered methods
}

 

// A ServerCodec implements reading of RPC requests and writing of
// RPC responses for the server side of an RPC session.
// The server calls ReadRequestHeader and ReadRequestBody in pairs
// to read requests from the connection, and it calls WriteResponse to
// write a response back. The server calls Close when finished with the
// connection. ReadRequestBody may be called with a nil
// argument to force the body of the request to be read and discarded.
type ServerCodec interface {
       ReadRequestHeader(*Request) error
       ReadRequestBody(interface{}) error
       // WriteResponse must be safe for concurrent use by multiple goroutines.
       WriteResponse(*Responseinterface{}) error

       Close() error
}

ReadRequestHeaderReadRequestBody一起使用从connection, nil读取body取出并丢弃最终使用的都是这几个函数,读取和发送response

只需要实现ServerCodec这个接口,就可以自定义服务端的编码解码器,实现自定义的rpc协议了。 Go rpc服务器端和客户端都是默认使用的Gob序列化协议数据。

 

 

1.3 Server端处理请求

 

 

func (server *ServerAccept(lis net.Listener) {
       for {
              connerr := lis.Accept()
              if err != nil {
                     log.Print("rpc.Serve: accept:"err.Error())
                     return
              
}
              go server.ServeConn(conn)
       }
}

 

Accept用来处理一个监听器,一直在监听客户端的连接,一旦监听器接收了一个连接,则还是交给 ServeConn 在另外一个goroutine中去处理:

// ServeConn runs the server on a single connection.
// ServeConn blocks, serving the connection until the client hangs up.
// The caller typically invokes ServeConn in a go statement.
// ServeConn uses the gob wire format (see package gob) on the
// connection. To use an alternate codec, use ServeCodec.
func (server *ServerServeConn(conn io.ReadWriteCloser) {
       buf := bufio.NewWriter(conn)
       srv := &gobServerCodec{
              rwc:    conn,
              dec:    gob.NewDecoder(conn),
              enc:    gob.NewEncoder(buf),
              encBuf: buf,
       }
       server.ServeCodec(srv)
}

 // 根据指定的codec进行协议解析 

 

// ServeCodec is like ServeConn but uses the specified codec to
// decode requests and encode responses.
func (server *ServerServeCodec(codec ServerCodec) {
       sending := new(sync.Mutex)
       for {
              servicemtypereqargvreplyvkeepReadingerr := server.readRequest(codec)
              if err != nil {
                     if debugLog && err != io.EOF {
                            log.Println("rpc:"err)
                     }
                     if !keepReading {
                            break
                     
}
                     // send a response if we actually managed to read a header.
                     if req != nil {
                            server.sendResponse(sendingreqinvalidRequestcodecerr.Error())
                            server.freeRequest(req)
                     }
                     continue
              
}
              go service.call(serversendingmtypereqargvreplyvcodec)
       }
       codec.Close()
}

 

解码request和编码response

 

func (server *ServerreadRequestHeader(codec ServerCodec)

读取头部信息,获取service和方法。

 

 

func (s *servicecall(server *Serversending *sync.Mutexmtype *methodTypereq *Requestargvreplyv reflect.Valuecodec ServerCodec) {
       mtype.Lock()
       mtype.numCalls++
       mtype.Unlock()
       function := mtype.method.Func
       // Invoke the method, providing a new value for the reply.
       returnValues := function.Call([]reflect.Value{s.rcvrargvreplyv})
       // The return value for the method is an error.
       errInter := returnValues[0].Interface()
       errmsg := ""
       if errInter != nil {
              errmsg = errInter.(error).Error()
       }
       server.sendResponse(sendingreqreplyv.Interface()codecerrmsg)
       server.freeRequest(req)
}

 

 returnValues := function.Call([]reflect.Value{s.rcvrargvreplyv})


0 0