go語言遊戲服務端開發(三)——服務機制

五邑隱俠發表於2021-09-18
五邑隱俠,本名關健昌,12年遊戲生涯。 本教程以Go語言為例。
 
P2P網路為服務程式間、服務程式與客戶端間通訊提供了便利,在這個基礎上可以搭建服務。
在服務層,通訊包可以通過定義協議號來確定該包怎樣處理。每個協議號對應一個Processor,Processor定義為一個interface
type Processor interface {
    OnHandleRequest(req *Request, resp *Response) (int32, error)
}

協議號又可以拆分為模組號和命令號。一個模組對應一個Service,該模組下每個命令對應一個Processor,通過map結構做對映

type Service struct {
    mapCmd2Processor map[uint16]Processor
}
Service提供方法新增、刪除、獲取Processor
func AddProcessor(cmd uint16, p Processor) error
func GetProcessor(cmd uint16) Processor
func RemoveProcessor(cmd uint16) error
提供個入口方法,把該模組的Service的請求分發到對應的Processor
func (s *Service) OnHandleRequest(req *Request, resp *Response) (int32, error) {
    p, ok := s.mapCmd2Processor[req.Cmd]
    if ok {
        return p.OnHandleRequest(req, resp)
    }
}
服務 Server 是 Service 的集合,通過模組號進行對映
type Server struct {
    mapMod2Service map[uint16]*Service
    rpc            *Rpc
}
同樣提供方法新增、刪除、獲取Service
func AddService(mod uint16, srv *Service) error
func GetService(mod uint16) *Service
func RemoveService(mod uint16) error
這樣當收到一個請求包,對協議號拆分為模組號和命令號,通過模組號獲取到對應的Service,呼叫Service的 OnHandleRequest 進行處理
serv := s.GetService(req.Mod)
if serv != nil {
    code, err := serv.OnHandleRequest(req, resp)
}
Server 基於 P2P 層,P2P的包是通用的格式,不同的遊戲服務端程式,都有可能有不同的包格式,例如,客戶端包格式和服務內部通訊的包格式是有差別的。為了讓服務通用,引入服務介面卡,在請求和響應時做預處理,轉化為通用的 Request 和 Response
type ServerAdapter interface {
    OnRequest(payload []byte) (*Request, error)
    OnResponse(pack *Response) ([]byte, error)
}

type Server struct {
    mapMod2Service map[uint16]*Service
    rpc            *Rpc
    
    adapter        ServerAdapter
}
這樣在服務層都是基於 Request 和 Response進行處理,由具體業務對業務包做轉換
type Request struct {
    Mod      uint16
    Cmd      uint16
    Payload  []byte
}

type Response struct {
    Mod      uint16
    Cmd      uint16
    Payload  []byte
}
服務 Server 還可以提供攔截器,攔截器的好處是對一些階段進行統一處理,而且可以通過插入新攔截器進行擴充套件,隨時都可以替換這個階段的邏輯(例如從 json 包變成 proto 包、增加二進位制頭等),攔截器可以針對3個階段: 請求處理前,請求處理後,響應傳送後
type Interceptor interface {
    OnPreHandle(req *Request, resp *Response) (int32, error)
    OnHandleCompletion(req *Request, resp *Response) (int32, error)
    OnResponseCompletion(req *Request, resp *Response) error
}
除了全域性攔截器,還可以新增針對某個模組 Service 的攔截器,對某個 Service 做特殊攔截處理
type InterceptorList []Interceptor

type Server struct {
    mapMod2Service map[uint16]*Service
    rpc            *Rpc
    
    adapter        ServerAdapter
    globalInterceptors InterceptorList
    mapMod2Interceptors map[uint16]InterceptorList
}
這樣一個請求的處理過程就變成
// adapter
req, err := s.adapter.OnRequest(payload)
resp := NewResponse(req)
// prehandle
interList, ok := s.mapMod2Interceptors[req.Mod]
s.prehandle(interList, ok, req, resp)
// handle
serv := s.GetService(req.Mod)
code, err := serv.OnHandleRequest(req, resp)
// handle complete
s.handleCompletion(interList, ok, req, resp)
s.push(resp)
// response complete
s.responseCompletion(interList, ok, req, resp)
服務機制介紹到這裡,接下來聊聊 RPC 機制

 

相關文章