45. 배치 메시지 스트림의 미지(unknown) 타입 처리 (C#)

난이도 상 해설 보기 →

결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커 (A)(B) 는 주목 위치 힌트다.

결함 코드 · C#
// ============================================================================
// [코드리뷰 문제] C# — 배치 메시지 스트림의 미지(unknown) 타입 처리
// ----------------------------------------------------------------------------
// 시나리오:
//   클라이언트는 한 번의 전송에 여러 논리 메시지를 배치(batch)로 묶어 보낸다.
//   각 메시지는 [type:u16][len:u16][payload:len] 형식이다. 프로토콜은 버전업으로
//   새 메시지 타입이 추가될 수 있으므로(전방 호환), 서버는 자신이 모르는 타입을
//   만나도 그 메시지를 건너뛰고 나머지를 계속 처리해야 한다.
//
// 요구사항:
//   - 알려진 타입은 처리하고, 모르는 타입은 len 만큼 정확히 건너뛴다.
//   - 손상/악성 입력(선언 len 이 남은 바이트보다 큼 등)에도 버퍼 밖을 읽지 않는다.
//   - 하나의 메시지 처리가 어긋나도 이후 메시지 경계가 밀리면 안 된다.
//
// 과제: (A) (B) 지점의 동작을 설명하고 수정안을 제시하라.
// ============================================================================

using System;

public sealed class BatchDecoder
{
    private const int HeaderSize = 4;          // type(2) + len(2)
    private const int KnownPayloadSize = 8;    // 현재 서버가 아는 타입들의 payload 크기

    public void Decode(ReadOnlySpan<byte> buf)
    {
        int off = 0;
        while (off + HeaderSize <= buf.Length)
        {
            ushort type = (ushort)(buf[off] | (buf[off + 1] << 8));
            ushort len  = (ushort)(buf[off + 2] | (buf[off + 3] << 8));
            off += HeaderSize;

            var payload = buf.Slice(off, len);   // (B)
            switch (type)
            {
                case 1: HandleMove(payload); break;
                case 2: HandleChat(payload); break;
                default: break;                  // 미지 타입: 무시
            }
            off += KnownPayloadSize;         // (A)
        }
    }

    private void HandleMove(ReadOnlySpan<byte> p) { /* ... */ }
    private void HandleChat(ReadOnlySpan<byte> p) { /* ... */ }
}
내 리뷰 · C#
내 답안 · 자동 저장

작성 후 위 해설 보기에서 모범 해설과 대조하세요.