너의 이름은

반짇고리·2026년 3월 22일

게임 서버 제작기

목록 보기
4/15


이전 포스팅 말미에 Welcome을 아주 짧게 언급했다.

그때는 “Session을 만들었으면 클라에게 알려줘야 한다” 정도로만 적었지만, 다시 보니 이 패킷을 그냥 처음 보내는 인사 정도로 넘기기는 어렵다.

그렇다면 자연스레 질문이 하나 남는다.

그 정체성을 클라는 언제 알게 되는가?

서버 안에서만 sessionId를 만들고 있으면 아무 의미가 없다. 서버는 “너는 1번 Session”이라고 생각하는데, 클라는 아직 아무것도 모른다. 소켓이 열렸고, 서버에 뭔가 보낼 수 있을 뿐이다.

처음에는 이 차이가 그렇게 커 보이지 않았다. 어차피 서버가 다 판단할 거라면 클라가 sessionId를 몰라도 되는 거 아닌가 싶었다.

하지만 Room에 들어가고, Ready를 누르고, 서버가 응답을 보내고, 클라가 자기 상태를 화면에 표시하려면 최소한 기준점 하나는 필요하다.

그 첫 기준점이 Welcome이었다. Hello, World! 같아서 뭔가 가벼워 보이지만 하는 일은 가볍지 않았다. 서버가 클라에게 처음으로 “너는 지금 이 서버에서 이런 런타임 식별자로 보인다”고 알려주는 패킷이기 때문이다.


이름을 누가 정하는가

처음 기준은 단순했다. 서버 권한 구조이기에 클라가 자기를 먼저 소개하지 않는다.

client -> server: 나는 7번 플레이어임

이렇게 클라가 자기주장을 펼치는 흐름은 피했다.

즉 서버가 먼저 말한다.

server -> client: 너의 sessionId는 7이다

작은 차이처럼 보이지만, 서버 권한 구조에서는 이 차이가 꽤 크다. 클라가 자기 식별자를 정해서 보내기 시작하면 서버는 그 값을 반드시 의심해야 한다.

이미 있는 값인지.
다른 사람의 값은 아닌지.
재사용된 값인지.
조작된 값은 아닌지.

물론 뒤로 가면 인증이나 토큰 같은 더 강한 기준도 필요해질 것이다. 하지만 이 시점에서 잡으려는 건 계정 보안이 아니다. 아직은 더 작다. 서버 프로세스 안에서 살아 있는 런타임 주체를 누가 이름 붙이는가.

나는 그 일을 서버가 해야 한다고 봤다.

Welcome은 권한을 클라에게 넘겨주는 패킷이 아니다. 서버가 만든 기준을 클라에게 건네는 패킷이다.

그 차이가 중요했다.


12바이트

일단 Welcome은 최소한으로 잡았다.

Size       2 bytes
Type       2 bytes
sessionId  8 bytes

전체 12바이트. (아직은 참 작고 소중하게 느껴지지만, 몇 개월 뒤에는 이마저도 크다고 느껴질지는 모르겠다.)

계정 정보도 없고, 닉네임도 없고, Room 정보도 없고, 현재 접속자 목록도 없다. 그냥 sessionId 하나만 내려준다.

처음에는 이런 생각도 했다. 어차피 처음 보내는 패킷인데 이것저것 같이 담으면 더 편하지 않을까.

하지만 이 패킷이 맡을 일은 적어도 아직까지는 많지 않다.

Welcome은 로그인 결과가 아니다. 프로필 응답도 아니고, Room snapshot도 아니다. 그냥 서버가 발급한 런타임 식별자를 알려주는 첫 패킷이다.

그래서 작게 두는 쪽이 더 낫다고 봤다. 첫 패킷부터 많은 의미를 넣으면, 연결이 열리는 순간부터 한 번에 너무 많은 걸 믿게 된다.

너는 지금 이 서버에서 이 sessionId로 보인다.

이 정도면 충분했다.


패킷이 된다는 것

그런데 Welcome을 설계하면서 숫자 하나 보내는 게 생각보다 많은 걸 고려해야 한다는 것을 깨달았다.

몇 바이트인지, 어떤 순서로 쓸지, 어떤 값이면 Welcome인지 정해야 했다. 상대가 엉뚱한 크기로 읽으면 실패해야 한다. 그래서 SizeType이 붙었다.

Size: 이 패킷은 어디까지인가
Type: 이 패킷은 무엇인가

처음에는 sessionId만 보내고 싶었다. 하지만 TCP 위에서 애플리케이션 패킷을 만들려면 적어도 경계는 필요했다.

나중에 이야기 하겠지만, TCP는 경계가 있는 메시지가 아니라 byte 스트림이다. 이걸 알고 나면 Welcome은 더 이상 단순한 인사말처럼 보이지 않는다. 첫 패킷이면서, 앞으로 TCP 패킷 계약이 어떤 식으로 생길지 보여주는 작은 샘플이 된다.

나는 여기서 처음으로 체감했다. 게임 서버에서 패킷은 그냥 구조체가 아니다. 서버와 클라가 서로 오해하지 않기 위한 약속인 것이다.


실제로 Welcome 받기

이 흐름은 테스트로 봐도 꽤 마음에 들었다. 함수 하나를 호출해서 sessionId가 나오는지 보는 정도로 끝내지 않았기 때문이다.

서버를 띄우고, 클라가 TCP로 붙고, 서버가 Welcome을 보낸다. 클라는 그 바이트를 읽고 다시 패킷으로 해석한다. 타입이 Welcome인지 확인하고, sessionId가 0이 아닌 유효한 값인지 확인하고, 여러 클라가 붙었을 때 서로 다른 sessionId를 받는지도 봤다.

이게 좋았던 이유는 간단하다.

진짜 경계에 가까웠다. 메모리 안에서 객체 하나를 만든 게 아니라, 실제 연결을 열고, 실제 바이트를 받고, 그 바이트를 다시 읽었다.

게임 서버의 ㄱ자도 만들지 않았지만 서버가 클라에게 처음으로 자기 기준을 말하는 흐름은 생겼다.


맺으며

Welcome은 만들고 보니 서버와 클라가 같은 기준으로 대화를 시작하게 만드는 첫 문장에 가까웠다.

소켓이 열리고, 서버가 Session을 만들었다. 그리고 서버는,

너 지금 sessionId=7임

게임 서버 시작까지 한참 남았지만, 어쨌든 대화의 기준은 생겼다. 작은 패킷 하나지만 서버 입장에서는 꽤 중요한 첫 문장이 된 것이다.

profile
Sapere Aude!

0개의 댓글