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

메시지 순서, 크기와 ACK

~13 min · protocol, ordering, ack, asyncapi

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

WebSocket 은 전송 순서를 보장해

연결 하나 안에서는 WebSocket 프레임이 보낸 순서대로 도착해. TCP 의 보장이 위 계층까지 이어지는 거야. 순서 뒤바뀜은 없지만 프로토콜 수준의 중복 제거도 없어. 재연결하면 이 보장은 초기화되고 새 연결은 완전히 독립적이야.

프레임 크기의 한계

프로토콜은 이론상 2^63바이트에 이르는 거대한 프레임을 허용하지만 실제 구현은 모두 상한을 둬. 운영 기본값은 대개 64KB~1MB 야. 더 큰 페이로드는 메타데이터가 있는 file.start, 바이너리 조각 흐름, file.end 처럼 명시적으로 나눠 보내. 논리적 메시지 하나가 프레임 하나라고 가정하면 안 돼.

애플리케이션 수준의 ACK

채팅 메시지나 결제 확인처럼 메시지가 반드시 전달되어야 한다면 애플리케이션 계층에서 ACK 를 만들어. 클라이언트가 순번과 함께 보내고 서버가 같은 순번의 ack 로 응답하며, 확인이 오지 않으면 클라이언트가 다시 보내는 방식이야. WebSocket 연결 자체와 독립적으로 설계하면 재연결도 견딜 수 있어.

AsyncAPI 로 문서화하기

AsyncAPI 는 사건 중심 메시지 API 를 위한 OpenAPI 와 같아. 채널, 작업, 메시지 스키마를 YAML 로 정의하고 문서, 모의 서버, 클라이언트 코드를 만들 수 있어. 메시지 type 이 몇 개를 넘어가면 충분히 가치가 있어.

Code

WebSocket 에서 파일을 조각내 올리기·javascript
async function uploadFile(ws, file) {
  const CHUNK = 64 * 1024;
  const total = Math.ceil(file.size / CHUNK);
  ws.send(JSON.stringify({
    type: 'file.start',
    data: { name: file.name, size: file.size, chunks: total },
  }));
  for (let i = 0; i < total; i++) {
    const slice = file.slice(i * CHUNK, (i + 1) * CHUNK);
    const buf = await slice.arrayBuffer();
    ws.send(buf);
  }
  ws.send(JSON.stringify({ type: 'file.end' }));
}
애플리케이션 수준 ACK 와 재시도·javascript
const unacked = new Map();
let nextSeq = 0;

function sendReliable(ws, type, data) {
  const seq = ++nextSeq;
  const msg = { seq, type, data };
  unacked.set(seq, { msg, attempts: 1 });
  ws.send(JSON.stringify(msg));
  setTimeout(() => retryIfStillUnacked(ws, seq), 5_000);
}

function retryIfStillUnacked(ws, seq) {
  const entry = unacked.get(seq);
  if (!entry) return;
  if (entry.attempts >= 3) {
    unacked.delete(seq);
    notifyUserOfFailure(seq);
    return;
  }
  entry.attempts += 1;
  ws.send(JSON.stringify(entry.msg));
  setTimeout(() => retryIfStillUnacked(ws, seq), 5_000);
}

ws.onmessage = (e) => {
  const m = JSON.parse(e.data);
  if (m.type === 'ack') unacked.delete(m.seq);
};

External links

Exercise

WebSocket 위에서 파일을 조각내 올리는 기능을 만들어. 5MB 파일을 64KB 조각으로 나누고 서버에서 다시 합쳐 디스크에 저장한 뒤 크기가 같은지 확인해. 업로드 중간에 연결을 끊어 서버에 일부 파일이 남는지 보고, file.resume 메시지를 추가해 다음 조각 번호부터 재개할 수 있게 해.

Progress

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

댓글 0

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

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