본문 바로가기
C.W.K.
Stream
Lesson 06 of 08 · published

바이너리 데이터

~11 min · browser, binary, dataview

Level 0Poller
0 XP0/60 lessons0/10 achievements
0/120 XP to next level120 XP to go0% complete

바이너리가 필요한 이유

JSON 은 사람이 읽고 디버깅하기 쉽지만 느리고 커. 멀티플레이어 게임의 위치, 시장 시세, 센서 스트림처럼 작고 빈번한 메시지에서는 JSON 의 부담이 대역폭 비용과 프레임 누락으로 드러나. 바이너리를 쓰면 페이로드 크기를 60~80% 줄이고 해석 시간도 더 크게 단축할 수 있어. 브라우저가 바이너리를 기본 지원하지만 인코더와 디코더는 직접 만들어야 해.

DataView 를 활용해

DataViewArrayBuffer 의 특정 바이트 위치에서 자료형이 있는 값을 읽고 써. 바이트 순서는 명시적으로 정해야 하는데, 보통 little-endian 을 뜻하는 true 를 넘겨. 그래야 같은 전송 형식을 JavaScript 클라이언트와 Python 서버가 함께 쓸 수 있어. 정해진 위치에 여러 필드를 한 버퍼로 묶으면 직접 만든 바이너리 프로토콜이 완성돼.

MessagePack 이나 Protobuf 를 골라야 할 때

직접 만든 바이너리 형식은 필드가 적고 엄격히 정의된 메시지에 잘 맞아. 프로토콜에 스키마 변경, 선택 필드, 중첩 구조가 생기면 JSON 을 바로 대체하면서 약 30% 작은 MessagePack 이나, .proto 정의가 필요하지만 압축 효율이 뛰어난 Protobuf 가 나아. 트랙 5 에서 다시 다룰 거야.

Code

플레이어 위치 묶고 풀기·javascript
ws.binaryType = 'arraybuffer';

// Encode: id(uint16) + x(int16) + y(int16) + flags(uint8)
function encodePos(id, x, y, flags) {
  const buf = new ArrayBuffer(7);
  const v = new DataView(buf);
  v.setUint16(0, id, true);
  v.setInt16(2, x, true);
  v.setInt16(4, y, true);
  v.setUint8(6, flags);
  return buf;
}

ws.send(encodePos(42, 150, -300, 0b0001));

ws.addEventListener('message', (e) => {
  if (!(e.data instanceof ArrayBuffer)) return;
  const v = new DataView(e.data);
  const id = v.getUint16(0, true);
  const x  = v.getInt16(2, true);
  const y  = v.getInt16(4, true);
  const flags = v.getUint8(6);
  applyPosition(id, x, y, flags);
});
프레임 하나에 여러 위치 담기·javascript
// 7 bytes per record, N records in one frame
function encodeAll(positions) {
  const buf = new ArrayBuffer(positions.length * 7);
  const v = new DataView(buf);
  positions.forEach((p, i) => {
    const o = i * 7;
    v.setUint16(o,     p.id, true);
    v.setInt16( o + 2, p.x,  true);
    v.setInt16( o + 4, p.y,  true);
    v.setUint8( o + 6, p.flags);
  });
  return buf;
}

External links

Exercise

같은 플레이어 위치 프로토콜을 JSON 과 바이너리로 각각 측정해. {id, x, y, flags} 갱신 1,000개를 JSON 으로 보내고, 다시 위의 7바이트 바이너리 형식으로 보내. 네트워크 탭에서 총 전송 바이트 수를 재고, performance.now()JSON.parseDataView 읽기를 감싸 1,000개를 해석하는 시간도 재. 두 비율을 적어 봐.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.