이제 웹 소켓을 이용한 실시간 데이터를 주고 받는 플랫포머 게임의 백엔드 개발 완성을 목적으로 리얼 타임 프로젝트를 시작한다.
이에 앞서 우선 강의 안에서 사전에 기획/구현한 파일들의 구조 및 기능, 그리고 활용된 주요 메서드를 정리해보는 것이 좋겠다.
간단히 정리하면 다음과 같다.
애플리케이션에서 사용될 에셋 데이터로 현재 json 형식으로
{
"name": "/* 에셋 명 */",
"version": "/* 적용 클라이언트 버전 */",
"data": [
/* 에셋 데이터 테이블 */
]
}
과 같은 형태로 저장되어 있다.
서빙할 static 정적 파일들의 저장소이다. 즉, 프론트엔드 단의 코드로 볼 수 있다.
client-server 간의 이벤트 처리를 담당하는 이벤트 핸들러.
애플리케이션의 초기화 처리를 담당하는 코드. 소켓 초기화, 이벤트 핸들러 등록, 전역 에셋 불러오기 등의 초기화 설정을 담당한다.
애플리케이션에서 사용되는 데이터 모델에 대한 처리를 담당하는 코드. stage와 user란 데이터 모델에 대해서 생성, 삭제와 getter, setter 등을 구현해 놓았다.
애플리케이션의 진입점으로 서버 시작, 초기화 및 라우팅, 미들웨어 설정.
애플리케이션에서 사용되는 상수 값들로 현재 접속가능한 클라이언트 버전을 포함.
이번 프로젝트는 node 기반에서 socket.io 라이브러리를 활용한 웹 소켓이 주된 내용인 만큼 해당 부분에 대한 공부가 선행되어야만 한다.
언제나처럼 새로운 라이브러리를 사용할 때에는 해당 공식 홈페이지와 documentation을 참고한다.
socket.io는 공식 문서에서의 설명에 따르면
Socket.IO is a library that enables low-latency, bidirectional and event-based communication between a client and a server.
클라이언트 서버 간에서 저지연성, 양방향, 이벤트 기반 통신에 쓰이는 라이브러리라고 요약된다.
그리고 공식 문서에서 추가적으로 설명하기를
Socket.IO is NOT a WebSocket implementation.
Socket.IO는 WebSocket에 기반하지만, 추가적인 메타데이터를 패킷에 제공하여 더 나은 연결 관리와 통신을 효율적으로 수행한다.
공식 문서에서 정리하는 주요 특징들은 다음과 같다.
웹 소켓 연결이 실패할 경우 HTTP 폴링으로 대체된다. 현재에는 많은 브라우저들이 웹 소켓을 지원하지만, 아직까지도 웹 소켓 연결을 만들어내지 못하는 미설정된 프록시를 통한 요청이 존재하기 때문이다.
알 수 없는 이유의 링크 단절과 같은 이유는 서버와 클라이언트 간의 웹 소켓 연결을 방해한다. Socket.IO에서는 주기적인 연결 상태 확인의 heartbeat 매커니즘을 포함시켜, 연결이 일시적으로 끊어지더라도 자동적으로 재연결시키도록 한다.
패킷은 클라이언트가 연결해제 시 자동적으로 버퍼에 담겨 재연결 시 전송된다.
이벤트 전송과 응답은 다음과 같은 방식으로 이루어진다.
// Sender
socket.emit("hello", "world", (response) => {
// 응답 로그"got it"
console.log(response);
});
//Receiver
socket.on("hello", (arg, callback) => {
console.log(arg);
// "world"
callback("got it");
});
timeout을 설정하는 것도 가능하다.
socket.timeout(5000).emit("hello", "world", (err, response) => {
if (err) {
// the other side did not acknowledge the event in the given delay
} else {
console.log(response); // "got it"
}
});
서버 단에서 모든 연결된 클라이언트들 내지는 일부 클라이언트들에게 전송하는 브로드캐스팅도 가능하다.
// to all connected clients
io.emit("hello");
// to all connected clients in the "news" room
io.to("news").emit("hello");
네임스페이스로 애플리케이션 로직을 단일 연결을 통해 분할 가능하도록 한다.
io.on("connection", (socket) => {
// classic users
});
io.of("/admin").on("connection", (socket) => {
// admin users
});
이러한 socket.io에서 클라이언트와 서버 간 연결에 있어서 이벤트 기반의 통신 및
브로드캐스팅/멀티캐스팅 기능과 멀티플렉싱하는 법을 예제 메서드를 통해 알아보았다.