Dispatcher

Dispatch?

  • 사전적 의미로는 “빨리 처리하다, 죽이다, 급파, 급송”
  • 컴퓨터에서는 프로세스를 CPU로 가져오는걸 Dispatch 라고 함
  • 또 자주 쓰이는 의미로는 이벤트 핸들러가 있음
    • 작업이 생기고, 그 작업을 알맞은 핸들러에게 보내주기 때문

이번 게임 서버에서 Dispatcher 구조

  • 기존에 있던 MessageType 에 맞게 알맞은 핸들러와 연결해주려고 함

  • 그리고 디스패처가 그냥 패킷 뿐만 아니라 접속된 정보를 같이 보내줘야 함
    • 왜냐면 그래야 핸들러가 패킷에 알맞은 응답을 접속 정보를 통해 반환할 수 있기 때문임
      • 접속 정보는 이전 시간에 정의했던 구조체 중에 Connection 안에 있음

Connection 간략 코드

type Connection struct {
    conn   net.Conn // <- 얘가 접속 정보를 가지고 있음
    writer *packet.PacketWriter
    reader *packet.PacketReader
}

Dispatcher 코드

package dispatch
 
import (
    "game-server/network"
    "reflect"
)
 
// 핸들러는 무조건 두 정보를 가져야 함 (연결 정보 + 메시지)
type HandlerFunc func(conn *network.Connection, msg any)
 
// MessageType에 대응하는 핸들러를 연결하는 딕셔너리(맵)
var handlers = map[reflect.Type]HandlerFunc{}
 
// reflect.Type은 런타임에 확인하는 타입임
 
// 핸들러 딕셔너리에 등록
func Register(msg any, handler HandlerFunc) {
    t := reflect.TypeOf(msg)
    handlers[t] = handler
}
 
// 핸들러 딕셔너리를 기반으로 디스패치
func Dispatch(conn *network.Connection, msg any) {
    t := reflect.TypeOf(msg)
    handler := handlers[t]
    handler(conn, msg)
}

Handler (Ping) 코드

package handler
 
import (
    "fmt"
    "game-server/dispatch"
    "game-server/network"
    "game-server/protocol"
    "time"
)
 
  
func init() {
    fmt.Println(time.Now(), " | Initialize Handler Started")
    dispatch.Register(&protocol.Ping{}, handlePing)
    fmt.Println(time.Now(), " | Initialize Handler Ended")
}
 
  
// MessageType : Ping 일 때 핸들러
func handlePing(conn *network.Connection, msg any) {
    _, ok := msg.(*protocol.Ping)
    // 참고 : 여기서 msg 는 any 라는 타입인데, any 는 말 그대로 뭐든 받을 수 있음
    // 타입 단언이라는 문법임. msg 안에 있는 데이터의 타입이 protocol.Ping 이면
    // 데이터를 꺼내서 req 에 넣고, 아니라면 실패함
    // 그래서 실제 데이터가 들어가는 req 와 성공 여부가 들어가는 ok 가 있음
 
    if !ok {
        return
    }
    
    fmt.Println(time.Now(), " | Ping Request")
 
    serverTime := time.Now().UnixMilli()
    fmt.Println(time.Now(), " | Pong Response : ", serverTime)
 
    pong := &protocol.Pong{
        Timestamp: serverTime,
    }
 
    conn.SendMessage(protocol.MessageType_PONG, pong)
}

다음에 할 것

  • 디스패쳐에 핸들러를 연결했으니, 실제로 서버를 열고 응답을 받아봐야 함