TCP 클라이언트-서버 기반의 게임 애플리케이션입니다. 클라이언트(client.js)와 서버(server.js), 그리고 여러 유틸리티 모듈로 구성되어 있습니다.
src.zip 파일에는 다음과 같은 구성 요소가 포함되어 있습니다:
config: 프로젝트 설정 파일.
config.js: 서버 포트, 호스트, 환경 변수와 같은 전역 설정을 관리합니다.constants: 애플리케이션에서 사용되는 상수 값 정의.
env.js: 개발, 프로덕션 등 환경별 상수를 정의합니다.header.js: 패킷 포맷 및 분석에 사용되는 헤더 상수를 정의합니다.event: 클라이언트-서버 간 이벤트 기반 통신을 관리.
onConnection.js: 클라이언트가 서버에 연결될 때 초기 설정을 처리합니다.onData.js: 클라이언트로부터 받은 데이터를 처리하고 응답을 결정합니다.onEnd.js: 클라이언트 연결 종료 시 동작을 정의합니다.onError.js: 오류 발생 시 이를 기록하고 처리합니다.init: 초기화 로직을 처리.
assets.js: 초기화 시 필요한 게임 자산 로드.index.js: 초기화 작업을 총괄하는 진입점.loadProtos.js: Protocol Buffers 정의를 로드하여 메시지 인코딩/디코딩에 사용합니다.protobuf: Protocol Buffers 정의 파일.
packetNames.js: 통신에 사용되는 패킷 이름을 정의합니다.request, response: 클라이언트 요청 및 서버 응답을 위한 Protocol Buffers 정의.server.js: 서버 로직.
init, event, utils 모듈을 사용합니다.utils: 유틸리티 함수 모음.
parser.js: 메시지 분석 및 응답 구성 유틸리티 함수.client.jsimport net from 'net';
import { getProtoMessages, loadProtos } from './src/init/loadProtos.js';
const TOTAL_LENGTH = 4; // 전체 길이를 나타내는 4바이트
const PACKET_TYPE_LENGTH = 1; // 패킷 타입을 나타내는 1바이트
net 모듈을 가져와 TCP 연결을 설정합니다.getProtoMessages와 loadProtos를 가져옵니다.TOTAL_LENGTH와 PACKET_TYPE_LENGTH는 패킷 헤더의 길이를 정의합니다.const readHeader = (buffer) => {
return {
length: buffer.readUInt32BE(0),
packetType: buffer.writeUInt8(TOTAL_LENGTH),
};
};
readHeader 함수는 버퍼에서 패킷 헤더를 읽어냅니다.length)와 패킷 유형(packetType)을 추출합니다.const sendPacket = (socket, packet) => {
const protoMessages = getProtoMessages();
const Packet = protoMessages.common.Packet;
if (!Packet) {
console.error('Packet 메시지를 찾을 수 없습니다.');
return;
}
const buffer = Packet.encode(packet).finish();
const packetLength = Buffer.alloc(TOTAL_LENGTH);
packetLength.writeUInt32BE(buffer.length + TOTAL_LENGTH + PACKET_TYPE_LENGTH, 0);
const packetType = Buffer.alloc(PACKET_TYPE_LENGTH);
packetType.writeUInt8(1, 0);
const packetWithLength = Buffer.concat([packetLength, packetType, buffer]);
socket.write(packetWithLength);
};
sendPacket 함수는 서버로 패킷을 전송합니다.const HOST = 'localhost';
const PORT = 5555;
const client = new net.Socket();
client.connect(PORT, HOST, async () => {
console.log('Connected to server');
await loadProtos();
const message = {
handlerId: 2,
userId: 'xyz',
payload: {},
clientVersion: '1.0.0',
sequence: 0,
};
sendPacket(client, message);
});
client.connect(PORT, HOST)로 서버에 연결합니다.loadProtos()를 호출하여 Protocol Buffers 정의를 로드하고, 메시지를 생성하여 서버로 전송합니다.client.on('data', (data) => {
const buffer = Buffer.from(data);
const { handlerId, length } = readHeader(buffer);
console.log(`handlerId: ${handlerId}`);
console.log(`length: ${length}`);
const headerSize = TOTAL_LENGTH + PACKET_TYPE_LENGTH;
const message = buffer.slice(headerSize);
console.log(`server 에게 받은 메세지: ${message}`);
});
readHeader를 통해 헤더 정보를 추출합니다.client.on('close', () => {
console.log('Connection closed');
});
client.on('error', (err) => {
console.error('Client error:', err);
});
server.jsconst net = require('net');
const { onConnection, onData, onEnd, onError } = require('./event');
const { loadProtos } = require('./init/loadProtos');
const PORT = 5555;
const server = net.createServer(async (socket) => {
await loadProtos();
console.log('Client connected');
socket.on('data', (data) => onData(socket, data));
socket.on('end', () => onEnd(socket));
socket.on('error', (err) => onError(err));
});
server.listen(PORT, () => {
console.log(`Server listening on port ${PORT}`);
});
5555에서 클라이언트 연결을 수신합니다.버퍼(Buffer): 바이너리 데이터를 임시로 저장하는 공간입니다. 버퍼를 통해 패킷의 길이와 유형을 관리하고 메시지를 처리합니다.
Protocol Buffers (protobufjs): 데이터 직렬화를 위해 사용되는 도구입니다. 이 프로젝트에서는 메시지 인코딩과 디코딩에 사용됩니다.
TCP 소켓 통신: 신뢰성 있는 데이터 전송을 보장하는 프로토콜입니다. Node.js의 net 모듈을 사용해 TCP 연결을 관리합니다.
헤더 정보: 메시지의 길이와 유형을 포함하는 정보로, 클라이언트와 서버 간의 통신을 원활하게 관리하기 위해 사용됩니다.