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)
}