창민 튜터님의 공룡점프 과제 피드백 중에 이런 내용이 있었다.
'데이터 동기화 메커니즘이 없는 게 잠재적으로 문제가 될 수 있다.'...
데이터 동기화?
여기서는 또 상태 동기화 라고 한다? '각 플레이어들의 레이턴시를 측정하여 최선의 시간을 찾아 위치를 계산하여 유저들에게 알려준다'...
동기화에 대한 요주는 일단 클라이언트와 서버가 정말로 같은 값을 보고 쓰고 있는지 인것 같고, 상태 동기화는 주로 캐릭터 위치 같은 것에 쓸수 있는 듯 하다.
이를테면 클라에서 (0, 0)에 있다가 (15, 15)로 이동했다면, 서버가 이걸 아무 검증로직 없이 받아들일 수는 없을 것이다. 어떤 형식에 맞춰 데이터를 주고 받을테고, 이 캐릭터의 이전 좌표와 속도와 스킬 사용 여부 등을 검증해서 정말로 거기 이동할 수 있었던 상황인지를 봐야 할 것.
-> 클라단 데이터를 서버 검증없이 그냥 받으면 배그 위치핵처럼 담 하나 넘었는데 은신중인 적 등뒤로 뿅 워프하게 되는 불상사가 생긴다.
보스의 체력상태를 모든 유저에게 동기화 해주는 것도 상태 동기화니까, 레이드 전투에서 활용할 수 있을 것이다.
엄밀히는 그때의 message와는 좀 다르다. 그때는 그냥 String값을 버퍼 객체로 만들어 헤더 만들고 패킷으로 조립해서 주고받는 정도였지만, 이제는 주고 받아야 할 메시지의 양도 늘어나고 메시지도 복잡해져서 String이 아니라 '프로토콜 버퍼 구조체' 라는 일종의 포장된 애라고 생각하자.
우리가 주고받을 바이트 배열은 이렇게 생겼는데, 전체길이와 패킷타입(이번엔 핸들러ID 대신 이게 들어갔다)을 제외하면 나머지가 protobuf다. 이 protobuf는 또 마트로슈카처럼 안에 무언가를 잔뜩 가지고 있는데... (후후😏)
protobuf의 뚜껑을 여니 전에 썼던 핸들러ID와 함께 이런 것들이 있었다. 공룡점프에서 다 봤던 요소들이구먼.
그리고 이 안에서도 진짜 본체는 payload.
이유는 간단하다. 사용할 수 있는 라이브러리가 많지 않기 때문. node로 TCP 서버를 구축하는 경우가 많지 않은 것이 근본적인 원인.
그렇다면 열심히 뚝딱뚝딱 해주자. 환경변수 관련한 상수값들을 관리하는 constants 디렉토리를 생성하고, 환경변수를 중앙집중 식으로 관리하는 env.js
부터 만들어준다.
그 다음에는 header 관련한 상수들을 관리하는 header.js를 만든다.
constants 셋팅이 다 되었으면 config 디렉토리를 만들고 그 안에 config.js
를 만들어 모든 변수는 이 config 파일을 통해 나가게끔 해준다.
지금 단계에서야 별거 아니어 보이니 귀찮을 수 있겠지만, 프로젝트가 커지면 포트번호나 호스트 같은 게 여러 군데에 들어갈 수 있다. 그 값들 다 바뀔때마다 일일이 찾아서 변경할 수 없으니 애초에 중앙집중 관리 형태로 만드는 것.
이벤트를 구분해서 관리하는것과 바이트배열에서 패킷 헤더를 빼내는것
여기 있던 소켓 이벤트에 대한 코드들을 각자 파일로 분리하려고 한다. events 라는 디렉토리를 만들고 각각 onData, onEnd, onError 등등을 만들어주자.
에잇 아니다. onConnection
이라는 파일 만들어서, server.js의 const server = net.createServer()
안에 인자로 있던 콜백들을 싹 빼와 onConnection이라는 함수의 내용물로 만들자.
???? 왜 () =>
가 두개지? socket은 언제받고 data는 언제 받아요?
이 형태 보면 밖에서 콜백으로 socket 받고 안에서 콜백으로 data나 err를 받는다. 밖에서 받는 그 socket이 혹시 필요할 수 있으니 다음과 같이 써준다.
갑자기 왜 빈 버퍼를? 이걸 이해하려면 데이터 스트림의 개념을 알아야 한다. 스트리밍 할때 그 스트림. 참고 블로그
버퍼는 데이터를 청크라는 조각으로 쪼개서 조금조금씩 주고받는다. 일종의 버킷(빠께쓰) 같은 개념이고 이게 꽉 찰때까지 기다렸다가 차면 통째로 옮겨준다는 것. 안 차면 찰 때까지 기다린다. 이게 바로 버퍼링.
(당신은 진정한 버퍼링 세대인가)