전용 로거 만들기

  • 일일히 앞에 시간 붙이는것도 귀찮고 해서 로거를 따로 만듬
  • log.New 를 사용함
func New(out io.Writer, prefix string, flag int) *log.Logger
  • log.New

    • out io.Writer : 어디다가 쓸 것인가 - 표준 출력, 에러, 파일, 메모리 등등 가능
    • prefix string : 모든 로그 앞에 붙일 문자열을 설정
    • flag int : 로그 포맷 제어 비트 플래그. date, time, microseconds 등등 있음
  • 여기서는 총 네 가지의 로거를 만들 것 : Network, Dispatch, Handler, Packet

func Init() {
    // log.New(출력, 접두사, 맨 앞에 포맷 제어)
    NetworkLogger = log.New(
        os.Stdout,
        "[Network] ",
        log.Ldate|log.Ltime|log.Lmicroseconds|log.Lshortfile,
    )
    
    DispatchLogger = log.New(
        os.Stdout,
        "[Dispatch] ",
        log.Ldate|log.Ltime|log.Lmicroseconds|log.Lshortfile,
    )
	...
}
  • 그리고 지금까지 err를 반환하던 곳에서 로거를 사용해 한 번씩 찍도록 만듬

서버 여는건 됐으니 실제로 패킷을 받아보기

상태 흐름

net.Listen
 └ Accept
    └ goroutine
       └ conn.Read
          └ Packet 디코딩
             └ dispatcher.Dispatch
                └ handlePing 호출
  • 한 클라이언트 당 하나의 고루틴을 가지고 계속 통신하게 될 것임

connection.go 코드 추가

func NewConnection(c net.Conn) *Connection {
    return &Connection{
        Conn:   c,
        Writer: packet.NewPacketWriter(),
        Reader: packet.NewPacketReader(),
    }
}
 
// 계속 패킷 받는 함수
func (conn *Connection) ReadLoop() {
    defer conn.Conn.Close() // 문제 생기면 알아서 연결 닫음
 
    buf := make([]byte, 4096)
 
    for {
        n, err := conn.Conn.Read(buf) // 바이트 배열에다가 읽어옴 (블로킹). 반환값은 읽어온 바이트 개수
        if err != nil {
            logger.NetworkLogger.Println("Read Loop Error : ", err.Error())
            return
        }
        msg, err := codec.DeserializePacket(buf[:n])
        dispatch.Dispatch(conn, msg)
    }
}

server.go 코드 수정

 
func StartServer() {
    // 1. 9000번 포트로 리스닝 시작
    ln, err := net.Listen("tcp", ":9000")
    if err != nil {
        logger.NetworkLogger.Fatalln("Server Listening Error : ", err.Error())
    }
 
    logger.NetworkLogger.Println("Server Listening on Port 9000")
 
    for {
        rawConn, err := ln.Accept() // 2. 클라이언트가 들어올 때 까지 블로킹
        if err != nil {
            logger.NetworkLogger.Println("Accept Error: ", err)
            continue
        }
 
        logger.NetworkLogger.Println("Client Connected : ", rawConn.RemoteAddr().String())
  
        conn := NewConnection(rawConn)
 
        go conn.ReadRoop()
    }
}

문제 발생!!!

  • dispatcher 패키지와 network 패키지 사이에 순환구조가 만들어져서 에러가 났음
  • 이를 어쩌지.. 하던 중 ChatGPT 가 도와줌
  • >> 인터페이스를 만들어라! <<
package common
 
import (
    "game-server/protocol"
    "google.golang.org/protobuf/proto"
)
type ConnContext interface {
    SendMessage(msgType protocol.MessageType, msg proto.Message) error
    Close() error
}
  • SendMessage와 Close 를 가지는 struct 는 ConnContext 인터페이스를 구현했다고 판단하도록 함
  • 따라서 ConnContext 만 가지고 패킷을 보내고 연결을 끊을 수 있음

다음에 할 것

  • 임시 클라이언트 만들기. 이게 없어서 아직 테스트를 못함