개발일지/TIL(Today I Learned)

2025-01-09 <스트림이란 무엇일까>

프린스 알리 2025. 1. 9.

내일배움캠프 Node.js 트랙 51일차

스트림이란 무엇일까

부트캠프 튜터님과 이야기하던 중, 이런 질문을 받게 되었다.
"TCP는 데이터를 통째로 보내나요?"
나는 배운대로 답을 했다.
"아니요. 스트림 형식으로 보낸다고 알고 있습니다."
그러자 튜터님은 또다시 질문하셨다.
"스트림 형식이 뭔데요?"

 

말문이 턱 막혔다. TCP가 스트림 소켓이란 건 앞서 소켓 프로그래밍을 공부하며 알게 되었지만, 정확히 스트림 형식이란 게 뭔지 몰랐기 때문이다.


이걸 아직도 알아볼 생각을 안 하고 있었다니 스스로 놀랍고 당혹스러웠다. 이렇게 된 김에 오늘 TIL에는 스트림 형식에 대해 적어볼까 한다. 이제부터 작성할 정보는 최근에 구입한 책 <게임 서버 프로그래밍>에서 발췌한 내용들이다.

스트림 형식

스트림이란 데이터의 흐름이다. TCP 프로토콜이 연결 지향이라는 건 우리가 익히 들어서 알고 있는 사실이다. 3-Way-Handshake를 통해 연결을 수립하고 호스트와 서버는 데이터를 주고 받는다. 이런 흐름 중의 하나가 스트림이며 스트림 안에 있는 데이터가 중간에 끊기느냐 아니냐는 오로지 우리의 몫이라고 한다.

 

왜냐하면 스트림은 바이트의 흐름일 뿐, 데이터의 경계를 딱히 구별하지 않기 때문이다. 요컨대 "이 데이터가 하나의 메시지다" 또는 "이 데이터는 끝났다"를 스스로 판단하지 않는다는 소리다.

 

 

단말기 A에서 b로 스트림 형태의 통신을 해본다고 가정하자. 내가 단말기 A에 넣은 어떤 데이터를 넣었더라도 단말기 B에서 꺼낸 데이터와 일치하리란 보장은 없다. 왜냐하면 몇 바이트를 읽었느냐에 따라 내가 넣은 데이터가 온전히 담기지 않았을 수 있기 때문이다. 그러나 A에서 보낸 스트림을 모두 이으면 그때에는 비로소 B에서 꺼낸 데이터와 같아진다.

 

때에 따라선 몇 조각의 스트림을 받느냐도 다를 수 있고, 데이터의 순서도 엉망일 수 있다.(왜냐하면 전송계층의 기반 계층인 네트워크 계층에서 패킷을 일단 Best Effort 방식으로 전송하기 때문) 우리는 이러한 한계를 극복하기 위해 패킷에 헤더를 붙이고 특정한 정보를 부여하여 신뢰성 있는 통신을 가능케 한다.(이것이 TCP 프로토콜의 의의)

 

예를 들면 전체 패킷의 길이를 먼저 적어주는 방법이 존재한다.

// 패킷 헤더를 만들기 위한 함수
const makeNotification = (message, type) => {
  // 패킷 길이 정보를 저장할 공간을 만든다 (4바이트 크기)
  const packetLength = Buffer.alloc(config.packet.totalLength);

  // 패킷 길이 정보를 적는다 (메시지 길이 + 타입 정보 + 헤더 길이)
  packetLength.writeUint32BE(
    message.length + config.packet.typeLength + config.packet.totalLength,
    0,
  );

  // 패킷 타입 정보를 저장할 공간을 만든다 (1바이트 크기)
  const packetType = Buffer.alloc(config.packet.typeLength);
  packetType.writeUInt8(type, 0); // 패킷 타입 정보 기록

  // 패킷 길이, 타입, 메시지를 하나의 버퍼로 합친다
  return Buffer.concat([packetLength, packetType, message]);
};

댓글