전용 로거 만들기
- 일일히 앞에 시간 붙이는것도 귀찮고 해서 로거를 따로 만듬
- 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 만 가지고 패킷을 보내고 연결을 끊을 수 있음
다음에 할 것
- 임시 클라이언트 만들기. 이게 없어서 아직 테스트를 못함