Server端
本篇文章主要是在Go net/rpc 的server.go包进行翻译,并添加注释之后会对client以及server进行总结,废话不多说 直接贴代码了。有不正确的地方还请多多指正。
package rpc
import (
"bufio"
"encoding/gob"
"errors"
"io"
"log"
"net"
"net/http"
"reflect"
"strings"
"sync"
"unicode"
"unicode/utf8"
)
const (
// Defaults used by HandleHTTP
// 默认使用的HandleHTTP
DefaultRPCPath = "/_goRPC_"
DefaultDebugPath = "/debug/rpc"
)
// Precompute the reflect type for error. Can't use error directly
// because Typeof takes an empty interface value. This is annoying.
// 反射获取error的类型,不能直接使用因为Typeof需要一个空的interface值。
var typeOfError = reflect.TypeOf((*error)(nil)).Elem()
type methodType struct {
sync.Mutex // protects counters 互斥锁
method reflect.Method
ArgType reflect.Type
ReplyType reflect.Type
numCalls uint
}
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 注册方法
}
// Request is a header written before every RPC call. It is used internally
// but documented here as an aid to debugging, such as when analyzing network traffic.
// 每次RCP请求调用之前写头。
// 它在内部使用但是在这里记录来帮助调试,就像分析网络信息。
type Request struct {
ServiceMethod string // format: "Service.Method" 格式化服务端的方法
Seq uint64 // sequence number chosen by client 客户端选择的序号
next *Request // for free list in Server 服务端的空闲列表
}
// Response is a header written before every RPC return. It is used internally
// but documented here as an aid to debugging, such as when analyzing
// network traffic.
// 每次RCP返回之前写头。
// 它在内部使用但是在这里记录来帮助调试,就像分析网络信息。
type Response struct {
ServiceMethod string // echoes that of the Request 请求的响应
Seq uint64 // echoes that of the request 请求的响应
Error string // error, if any. 任何错误
next *Response // for free list in Server 服务端的空闲列表
}
// Server represents an RPC Server.
// 一个RPC服务的结构体
type Server struct {
mu sync.RWMutex // protects the serviceMap 互斥锁,保护serviceMap
serviceMap map[string]*service
reqLock sync.Mutex // protects freeReq 互斥锁保护freeReq
freeReq *Request
respLock sync.Mutex // protects freeResp 互斥锁保护freeResp
freeResp *Response
}
// NewServer returns a new Server.
// NewServer返回一个新的Server
func NewServer() *Server {
return &Server{serviceMap: make(map[string]*service)}
}
// DefaultServer is the default instance of *Server.
// 一个默认的*Server的实例
var DefaultServer = NewServer()
// Is this an exported - upper case - name?
// name是否为大写
func isExported(name string) bool {
rune, _ := utf8.DecodeRuneInString(name)
return unicode.IsUpper(rune)
}
// Is this type exported or a builtin?
// 这个类型是导出的 还是内置的
func isExportedOrBuiltinType(t reflect.Type) bool {
for t.Kind() == reflect.Ptr {
t = t.Elem()
}
// PkgPath will be non-empty even for an exported type,
// so we need to check the type name as well.
// PkgPath即使为导出类型也不会为空,所以我们最好检查类型名
return isExported(t.Name()) || t.PkgPath() == ""
}
// Register publishes in the server the set of methods of the
// receiver value that satisfy the following conditions:
// - exported method of exported type
// - two arguments, both of exported type
// - the second argument is a pointer
// - one return value, of type error
// It returns an error if the receiver is not an exported type or has
// no suitable methods. It also logs the error using package log.
// The client accesses each method using a string of the form "Type.Method",
// where Type is the receiver's concrete type.
/*
在服务器上注册并发布的一系列方法,需要满足以下条件:
1 导出的方法和导出的类别
2 两个参数都是导出类别
3 第二个参数是一个指针
4 一个返回值,类型错误
如果接收者不是一个导出的类型或者没有合适的方法将返回一个错误。
它也会使用package log书写错误日志。客户端使用"Type.Method"字符串访问每个方法,
类型是接收者的具体类型。
*/
func (server *Server) Register(rcvr interface{}) error {
return server.register(rcvr, "", false)
}
// RegisterName is like Register but uses the provided name for the type
// instead of the receiver's concrete type.
// RegisterName与Register类似,但是使用传入的名字作为类型,代替接收者的具体类型
func (server *Server) RegisterName(name string, rcvr interface{}) error {
return server.register(rcvr, name, true)
}
func (server *Server) register(rcvr interface{}, name string, useName bool) error {
server.mu.Lock()
defer server.mu.Unlock()
if server.serviceMap == nil {
server.serviceMap = make(map[string]*service)
}
s := new(service)
s.typ = reflect.TypeOf(rcvr) // 导出的类别
s.rcvr = reflect.ValueOf(rcvr) // 导出的方法
sname := reflect.Indirect(s.rcvr).Type().Name()
if useName {
sname = name
}
if sname == "" {
s := "rpc.Register: no service name for type " + s.typ.String()
log.Print(s)
return errors.New(s)
}
if !isExported(sname) && !useName {
s := "rpc.Register: type " + sname + " is not exported"
log.Print(s)
return errors.New(s)
}
if _, present := server.serviceMap[sname]; present {
return errors.New("rpc: service already defined: " + sname)
}
s.name = sname
// Install the methods 安装方法,返回一个类型匹配的方法
s.method = suitableMethods(s.typ, true)
if len(s.method) == 0 {
str := ""
// To help the user, see if a pointer receiver would work.
// 查看一个指针接收者是否正常工作
method := suitableMethods(reflect.PtrTo(s.typ), false)
if len(method) != 0 {
str = "rpc.Register: type " + sname + " has no exported methods of suitable type (hint: pass a pointer to value of that type)"
} else {
str = "rpc.Register: type " + sname + " has no exported methods of suitable type"
}
log.Print(str)
return errors.New(str)
}
server.serviceMap[s.name] = s
return nil
}
// suitableMethods returns suitable Rpc methods of typ, it will report
// error using log if reportErr is true.
// suitableMethods返回一个适当类型的Rpc方法,如果reportErr为true打印日志
func suitableMethods(typ reflect.Type, reportErr bool) map[string]*methodType {
methods := make(map[string]*methodType) //方法类别的结构体
for m := 0; m < typ.NumMethod(); m++ { // 小于方法集中的数量
method := typ.Method(m) // 返回的方法的类型字段给出方法签名
mtype := method.Type
mname := method.Name
// Method must be exported. 方法必须为导出的
if method.PkgPath != "" {
continue
}
// Method needs three ins: receiver, *args, *reply.
// 方法需要3个值,接收者,参数指针,返回指针
if mtype.NumIn() != 3 {
if reportErr {
log.Println("method", mname, "has wrong number of ins:", mtype.NumIn())
}
continue
}
// First arg need not be a pointer.
// 第一参数必须不为指针
argType := mtype.In(1)
if !isExportedOrBuiltinType(argType) { //是否为导出类型或者内建类型
if reportErr {
log.Println(mname, "argument type not exported:", argType)
}
continue
}
// Second arg must be a pointer.
// 第二个参数必须是一个指针
replyType := mtype.In(2)
if replyType.Kind() != reflect.Ptr { // 返回具体的种类
if reportErr {
log.Println("method", mname, "reply type not a pointer:", replyType)
}
continue
}
// Reply type must be exported.
// 返回类型必须为导出的
if !isExportedOrBuiltinType(replyType) {
if reportErr {
log.Println("method", mname, "reply type not exported:", replyType)
}
continue
}
// Method needs one out. 需要一个方法
if mtype.NumOut() != 1 { // NumOut返回一个函数类型的输出参数计数
if reportErr {
log.Println("method", mname, "has wrong number of outs:", mtype.NumOut())
}
continue
}
// The return type of the method must be error.
// 该方法的返回类型必须是错误的
if returnType := mtype.Out(0); returnType != typeOfError {
if reportErr {
log.Println("method", mname, "returns", returnType.String(), "not error")
}
continue
}
methods[mname] = &methodType{method: method, ArgType: argType, ReplyType: replyType}
}
return methods
}
// A value sent as a placeholder for the server's response value when the server
// receives an invalid request. It is never decoded by the client since the Response
// contains an error when it is used.
// 当服务器收到无效的请求时服务端返回一个值做为占位符。它永远不会被客户端解码,直到它被使用响应包含一个错误
var invalidRequest = struct{}{}
func (server *Server) sendResponse(sending *sync.Mutex, req *Request, reply interface{}, codec ServerCodec, errmsg string) {
resp := server.getResponse()
// Encode the response header 编码响应头
resp.ServiceMethod = req.ServiceMethod //RPC服务的结构体
if errmsg != "" {
resp.Error = errmsg
reply = invalidRequest
}
resp.Seq = req.Seq
sending.Lock()
err := codec.WriteResponse(resp, reply) //WriteResponse并发安全的
if debugLog && err != nil {
log.Println("rpc: writing response:", err)
}
sending.Unlock()
server.freeResponse(resp)
}
func (m *methodType) NumCalls() (n uint) {
m.Lock()
n = m.numCalls
m.Unlock()
return n
}
func (s *service) call(server *Server, sending *sync.Mutex, mtype *methodType, req *Request, argv, replyv reflect.Value, codec 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.rcvr, argv, replyv})
// The return value for the method is an error.
// 这个方法的返回值是一个错误
errInter := returnValues[0].Interface()
errmsg := ""
if errInter != nil {
errmsg = errInter.(error).Error()
}
server.sendResponse(sending, req, replyv.Interface(), codec, errmsg)
server.freeRequest(req) // 释放
}
type gobServerCodec struct {
rwc io.ReadWriteCloser
dec *gob.Decoder // 解码
enc *gob.Encoder // 编码
encBuf *bufio.Writer
closed bool
}
func (c *gobServerCodec) ReadRequestHeader(r *Request) error {
return c.dec.Decode(r)
}
func (c *gobServerCodec) ReadRequestBody(body interface{}) error {
return c.dec.Decode(body)
}
func (c *gobServerCodec) WriteResponse(r *Response, body interface{}) (err error) {
if err = c.enc.Encode(r); err != nil {
if c.encBuf.Flush() == nil {
// Gob couldn't encode the header. Should not happen, so if it does,
// shut down the connection to signal that the connection is broken.
// Gob不能编码头.不会发生,如果发生了,关闭连接表明连接损坏。
log.Println("rpc: gob error encoding response:", err)
c.Close()
}
return
}
if err = c.enc.Encode(body); err != nil {
if c.encBuf.Flush() == nil {
// Was a gob problem encoding the body but the header has been written.
// Shut down the connection to signal that the connection is broken.
// 这是一个gob的问题编码了body但是已经写了头
// 关闭连接表明连接损坏。
log.Println("rpc: gob error encoding body:", err)
c.Close()
}
return
}
return c.encBuf.Flush()
}
func (c *gobServerCodec) Close() error {
if c.closed {
// Only call c.rwc.Close once; otherwise the semantics are undefined.
// 只能调用c.rwc.Close一次。另外的语义未定义
return nil
}
c.closed = true
return c.rwc.Close()
}
// 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.
// ServeConn运行这个server在一个单独连接。
// ServeConn块,为连接提供服务直到客户端挂起
// 调用者使用go ServeConn调用。
// ServeConn在连接中使用gob包进行写格式化(详见gob包)。使用另一种编码使用ServeCodec。
func (server *Server) ServeConn(conn io.ReadWriteCloser) {
buf := bufio.NewWriter(conn)
srv := &gobServerCodec{
rwc: conn,
dec: gob.NewDecoder(conn),
enc: gob.NewEncoder(buf),
encBuf: buf,
}
server.ServeCodec(srv)
}
// ServeCodec is like ServeConn but uses the specified codec to
// decode requests and encode responses.
// ServeCodec与ServeConn相似但是使用指定的编码器来解码请求编码返回。
func (server *Server) ServeCodec(codec ServerCodec) {
sending := new(sync.Mutex)
for {
service, mtype, req, argv, replyv, keepReading, err := 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(sending, req, invalidRequest, codec, err.Error())
server.freeRequest(req)
}
continue
}
go service.call(server, sending, mtype, req, argv, replyv, codec)
}
codec.Close()
}
// ServeRequest is like ServeCodec but synchronously serves a single request.
// It does not close the codec upon completion.
// ServeRequest就像是ServeCodec但是同步服务的请求。它在完成后不关闭编解码器。
func (server *Server) ServeRequest(codec ServerCodec) error {
sending := new(sync.Mutex)
service, mtype, req, argv, replyv, keepReading, err := server.readRequest(codec)
if err != nil {
if !keepReading {
return err
}
// send a response if we actually managed to read a header.
// 如果我们读到了头,发送一个响应
if req != nil {
server.sendResponse(sending, req, invalidRequest, codec, err.Error())
server.freeRequest(req)
}
return err
}
service.call(server, sending, mtype, req, argv, replyv, codec)
return nil
}
// 获取空闲列表中的Request
func (server *Server) getRequest() *Request {
server.reqLock.Lock()
req := server.freeReq
if req == nil {
req = new(Request)
} else {
server.freeReq = req.next
*req = Request{}
}
server.reqLock.Unlock()
return req
}
// 释放
func (server *Server) freeRequest(req *Request) {
server.reqLock.Lock()
req.next = server.freeReq
server.freeReq = req
server.reqLock.Unlock()
}
// 获取响应的结构体指针
func (server *Server) getResponse() *Response {
server.respLock.Lock()
resp := server.freeResp
if resp == nil {
resp = new(Response)
} else {
server.freeResp = resp.next
*resp = Response{}
}
server.respLock.Unlock()
return resp
}
// 释放
func (server *Server) freeResponse(resp *Response) {
server.respLock.Lock()
resp.next = server.freeResp
server.freeResp = resp
server.respLock.Unlock()
}
func (server *Server) readRequest(codec ServerCodec) (service *service, mtype *methodType, req *Request, argv, replyv reflect.Value, keepReading bool, err error) {
service, mtype, req, keepReading, err = server.readRequestHeader(codec)
if err != nil {
if !keepReading {
return
}
// discard body 传入nil迫使放弃body
codec.ReadRequestBody(nil)
return
}
// Decode the argument value. 解码参数
argIsValue := false // if true, need to indirect before calling. 如果为真需要调用前间接处理
if mtype.ArgType.Kind() == reflect.Ptr {
argv = reflect.New(mtype.ArgType.Elem()) // 返回一个指针类型
} else {
argv = reflect.New(mtype.ArgType)
argIsValue = true
}
// argv guaranteed to be a pointer now. 参数保证为指针
if err = codec.ReadRequestBody(argv.Interface()); err != nil {
return
}
if argIsValue {
argv = argv.Elem()
}
replyv = reflect.New(mtype.ReplyType.Elem())
return
}
func (server *Server) readRequestHeader(codec ServerCodec) (service *service, mtype *methodType, req *Request, keepReading bool, err error) {
// Grab the request header. 获取请求头
req = server.getRequest()
err = codec.ReadRequestHeader(req)
if err != nil {
req = nil
if err == io.EOF || err == io.ErrUnexpectedEOF {
return
}
err = errors.New("rpc: server cannot decode request: " + err.Error())
return
}
// We read the header successfully. If we see an error now,
// we can still recover and move on to the next request.
// 我们成功的读取头,如果我们现在看到了一个错误,我们仍然可以恢复并继续执行下一个请求
keepReading = true
dot := strings.LastIndex(req.ServiceMethod, ".")
if dot < 0 {
err = errors.New("rpc: service/method request ill-formed: " + req.ServiceMethod)
return
}
serviceName := req.ServiceMethod[:dot]
methodName := req.ServiceMethod[dot+1:]
// Look up the request.查找请求
server.mu.RLock()
service = server.serviceMap[serviceName]
server.mu.RUnlock()
if service == nil {
err = errors.New("rpc: can't find service " + req.ServiceMethod)
return
}
mtype = service.method[methodName]
if mtype == nil {
err = errors.New("rpc: can't find method " + req.ServiceMethod)
}
return
}
// Accept accepts connections on the listener and serves requests
// for each incoming connection. Accept blocks until the listener
// returns a non-nil error. The caller typically invokes Accept in a
// go statement.
// Accept接收监听的连接。并为每一个进入的连接提供请求。Accept锁住直到监听返回non-nil错误。
// 调用者使用go语句调用Accept。
func (server *Server) Accept(lis net.Listener) {
for {
conn, err := lis.Accept()
if err != nil {
log.Print("rpc.Serve: accept:", err.Error())
return
}
go server.ServeConn(conn)
}
}
// Register publishes the receiver's methods in the DefaultServer.
// Register在DefaultServe发布接收方法
func Register(rcvr interface{}) error { return DefaultServer.Register(rcvr) }
// RegisterName is like Register but uses the provided name for the type
// instead of the receiver's concrete type.
// RegisterName与Register类似但是使用提供的名字作为类型代替接收的具体类型。
func RegisterName(name string, rcvr interface{}) error {
return DefaultServer.RegisterName(name, rcvr)
}
// 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.
/*
ServerCodec实现了对RPC会话服务器端的RPC请求和编写RPC响应的读取。服务成对的
调用ReadRequestHeader和ReadRequestBody从链接中读请求,调用WriteResponse讲
响应写回。当链接结束时服务调用Close。ReadRequestBody可能会传入一个nil以强
制要求读取和丢弃请求的body
*/
type ServerCodec interface {
ReadRequestHeader(*Request) error
ReadRequestBody(interface{}) error
// WriteResponse must be safe for concurrent use by multiple goroutines.
// WriteResponse必须是并发安全的
WriteResponse(*Response, interface{}) error
Close() error
}
// ServeConn runs the DefaultServer 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.
/*
ServeConn在一个链接上运行DefaultServer。
ServeConn锁住,为链接提供服务直到客户端挂起
调用者使用go语句调用ServeConn。
ServeConn使用gob包在链接中格式化的写入。
要使用另一种编码使用ServeCodec
*/
func ServeConn(conn io.ReadWriteCloser) {
DefaultServer.ServeConn(conn)
}
// ServeCodec is like ServeConn but uses the specified codec to
// decode requests and encode responses.
// ServeCodec与ServeConn类似但是使用指定的编码器来解码请求编码响应
func ServeCodec(codec ServerCodec) {
DefaultServer.ServeCodec(codec)
}
// ServeRequest is like ServeCodec but synchronously serves a single request.
// It does not close the codec upon completion.
// ServeRequest与ServeCodec相似,但是同步一个服务的请求。它不会再完成时关闭。
func ServeRequest(codec ServerCodec) error {
return DefaultServer.ServeRequest(codec)
}
// Accept accepts connections on the listener and serves requests
// to DefaultServer for each incoming connection.
// Accept blocks; the caller typically invokes it in a go statement.
/*
Accept接收监听的连接。并为每一个进入的连接提供请求。Accept锁住;
调用者使用go语句调用Accept。
*/
func Accept(lis net.Listener) { DefaultServer.Accept(lis) }
// Can connect to RPC service using HTTP CONNECT to rpcPath.
// 连接到RPC服务使用HTTP CONNECT
var connected = "200 Connected to Go RPC"
// ServeHTTP implements an http.Handler that answers RPC requests.
// ServeHTTP执行http.Handler应答RPC请求。
func (server *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
if req.Method != "CONNECT" {
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
w.WriteHeader(http.StatusMethodNotAllowed)
io.WriteString(w, "405 must CONNECT\n")
return
}
conn, _, err := w.(http.Hijacker).Hijack()
if err != nil {
log.Print("rpc hijacking ", req.RemoteAddr, ": ", err.Error())
return
}
io.WriteString(conn, "HTTP/1.0 "+connected+"\n\n")
server.ServeConn(conn)
}
// HandleHTTP registers an HTTP handler for RPC messages on rpcPath,
// and a debugging handler on debugPath.
// It is still necessary to invoke http.Serve(), typically in a go statement.
/*
HandleHTTP再RPCPath注册一个HTTP handler作为RPC的消息。
它必须调用http.Serve(),再go语句中调用。
*/
func (server *Server) HandleHTTP(rpcPath, debugPath string) {
http.Handle(rpcPath, server)
http.Handle(debugPath, debugHTTP{server})
}
// HandleHTTP registers an HTTP handler for RPC messages to DefaultServer
// on DefaultRPCPath and a debugging handler on DefaultDebugPath.
// It is still necessary to invoke http.Serve(), typically in a go statement.
/*
HandleHTTP将RPC消息的HTTP处理程序注册到DefaultRPCPath上的DefaultServer和DefaultDebugPath上的调试处理程序。
它必须调用http.Serve(),再go语句中调用。
*/
func HandleHTTP() {
DefaultServer.HandleHTTP(DefaultRPCPath, DefaultDebugPath)
}