TIL

2024년 10월 21일 TIL

kagan-draca 2024. 10. 21. 22:30

https://kagan-draca.tistory.com/326

 

2-1 실전 게임 서버 만들기

1. 사용할 라이브러리들 1) dotenvdotenv는 환경 변수를 .env 파일에 저장하고 이를 Node.js 어플리이케션에 로드개발자가 코드에서 직접 환경 변수를 설정하는 대신 별도의 파일로 관리할 수 있게 해

kagan-draca.tistory.com

https://kagan-draca.tistory.com/327

 

2-2 중앙집중식 환경변수 관리

1. 중앙 집중식 관리모든 환경 변수와 상수는 한 곳에서 관리, 다른 파일에서 동일한 값을 사용하여도 일관성을 유지변경이 필요할 때 한 곳에서만 수정하면 된다.환경 변수, 상수의 직접 사용이

kagan-draca.tistory.com

https://kagan-draca.tistory.com/328

 

2-3 (중요)이벤트 구분, 바이트 배열 분해

1. 이벤트, 패킷 헤더이벤트를 구분해서 관리할 수 있다.바이트 배열에서 패킷 헤더를 구분할 수 있다. 1) 소켓 이벤트 분리하기const server = net.createServer((socket) => {  console.log(`Client connected from ${so

kagan-draca.tistory.com

 

오늘은 위와 같이 TCP socket 통신을 배우고 정리해봤다.

이 중에서 가장 재미있는 내용은,

 

클라이언트가 보낸 packet (16진수 형태로 Buffer에 담겨, Header 정보와 Data가 붙어 있는 중)을 서버가 처리하는 로직이었다.

 

export const onData = (socket) => (data) => {
  //console.log(data);

  socket.buffer = Buffer.concat([socket.buffer, data]);
  // 기본 버퍼에 새로 수신된 데이터 추가하기

  const totalHeaderLength = config.packet.totalLength + config.packet.typeLength;

  // 버퍼의 해버 크기 보다 큰 경우 => 그때부터 진짜 message, data가 오는 상황이 된다.
  while (socket.buffer.length >= totalHeaderLength) {
    const length = socket.buffer.readUInt32BE(0);
    // 버퍼에 0 ~ 4Byte(4Byte 크기) 까지는 패킷 길이 정보
         
    const packetType = socket.buffer.readUInt8(config.packet.totalLength);
    // 4Byte ~ 5Byte(1Byte 크기) 만큼은 packet의 타입

    if (socket.buffer.length >= length) {
      // 퍼버의 현재 길이가 원하는 버퍼의 사이즈 보다 크거나 같을 경우

      const packet = socket.buffer.slice(totalHeaderLength, length);
      // 해더 부분을 제거해서 원하는 packet Data만 가져온다.
      socket.buffer = socket.buffer.slice(length);
      // 남은 해더 부분도 제거해서 다음 이벤트에 따른 Header와 packet Data 정보를 기다린다.
      console.log(`length : ${length}, packetType : ${packetType}`);
      console.log(`packet : ${packet}`);
    } else break;
    // 아직 전체 패킷이 도착하지 않았을 때
  }
};

위와 같은 로직으로,

 

그림을 통해 이해하자면, 클라이언트가 Buffer로 

 

20 Byte의 Packet을 보냈을 때,

(실질적인 내용물 => Packet Data는 15 Byte)

 

Packet Length로 클라이언트가 보낼 Packet의 전체 크기를 Buffer에 16진수 형태의 4Byte로 보내게 되고,

Packet Type을 Buffer에 담아 16진수 형태의 1Byte 크기로 보내게 된다.

 

이때, Packet은 잘게 쪼개져 서버로 보내게 되고, 이를 서버가

  socket.buffer = Buffer.concat([socket.buffer, data]);

버퍼로 받게 됩니다.

  const totalHeaderLength = config.packet.totalLength + config.packet.typeLength;
while (socket.buffer.length >= totalHeaderLength) {

while의 조건으로 socket.buffer.length >= totalHeaderLength(해더의 크기)(5 Byte)를 줘

현재 sockbuffer가 해더의 크기 보다 클 경우 (=> , 지금부터 받는 서버에 오는 datapacket Data) 반복문을 동작 시킵다.

 

while 안에서는

    const length = socket.buffer.readUInt32BE(0);
    // 버퍼에 0 ~ 4Byte(4Byte 크기) 까지는 패킷 길이 정보

0 ~ 32 bit(4 Byte) 만큼 자르고 그 안의 16진수 값을 10진수 정수로 바꿉니다.

이를 바탕으로 Packet의 해더와 Packet Data의 크기 입니다. 즉, Packet의 전체 크기를 알 수 있게 됩니다.

 

    const packetType = socket.buffer.readUInt8(config.packet.totalLength);
    // 4Byte ~ 5Byte(1Byte 크기) 만큼은 packet의 타입

로 4Byte 위치에서 부터 8bit(1Byte)만큼 1Byte 크기를 잘라 안의 16진수 값을

10진수로 변환해 packet의 타입 정보를 알아냅니다.

 

그 후,

 

    if (socket.buffer.length >= length) {
      // 퍼버의 현재 길이가 원하는 버퍼의 사이즈 보다 크거나 같을 경우

socket.buffer.length >= length

즉, 현재 socket의  buffer에 들어온 data 크기가 해더로 알게 된 packet의 크기와 같거나 크다면

=> 받아야 할 data를 받았거나 더 받았다면,

 

      const packet = socket.buffer.slice(totalHeaderLength, length);
      // 해더 부분을 제거해서 원하는 packet Data만 가져온다.

현재 socket.buffer 안의 packetData를 slice로 해더에서부터 전체 길이만큼 자릅니다

=> 해더를 제외한 실제 packet Data만 남긴다.

(붉은 영역 네모 자르기)

      socket.buffer = socket.buffer.slice(length);
      // 남은 해더 부분도 제거해서 다음 이벤트에 따른 Header와 packet Data 정보를 기다린다.

 socket.buffer.slice(length)로 0 ~ 해더 길이 만큼

남은 socket.buffer의 packet을 제거해 다음 이벤트에 따른 data를 받을 준비를 합니다.

    } else break;
    // 아직 전체 패킷이 도착하지 않았을 때

그리고, 위의 if문에 부합하지 않으면 break로 다음 패킷 조각이 올 때 까지 기다립니다.

 

위와 같은 과정을 잘 응용하면, 이미지, 그림, 텍스트, 동영상 등 모든 데이터를 클라이언트에게서 받아와 서버가 처리할 수 있을 것 같

'TIL' 카테고리의 다른 글

2024년 10월 17일 TIL  (0) 2024.10.17
2024년 10월 14일 TIL (15일 수정 내용 포함)  (0) 2024.10.16
2024년 10월 11일 TIL  (0) 2024.10.12
2024년 10월 10일 TIL  (0) 2024.10.11
2024년 10월 7일 TIL  (0) 2024.10.08