39. 수신 버퍼 컴팩션 누락: 부분 프레임 유실로 인한 프레임 desync (C#)

난이도 중 해설 보기 →

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

결함 코드 · C#
// 시나리오: TCP 게임 세션의 수신 파이프라인.
// 프레임 포맷: [ushort length][payload(length 바이트)]  (리틀 엔디안, length는 payload 길이)
// TCP는 스트림이라 한 번의 Receive가 프레임 경계와 무관하게 임의 바이트를 준다:
//   - 한 번에 여러 프레임이 뭉쳐 오기도 하고(N개 완결 + 다음 프레임의 앞부분 일부)
//   - 한 프레임이 여러 번에 걸쳐 쪼개져 오기도 한다.
//
// 요구사항:
//  1) 완결된 프레임만 골라 순서대로 디스패치한다.
//  2) 아직 덜 온 부분 프레임의 바이트는 버리지 말고 보존해, 다음 수신분과 이어붙여 파싱한다.
//  3) 어떤 조각 경계로 쪼개져 와도 프레임 경계가 어긋나선 안 된다.
//
// 아래 수신기에는 이 요구사항을 위반하는 지점이 있다. (A)(B)를 중심으로 진단·수정하라.

using System;

public class FrameReceiver
{
    private readonly byte[] _buffer = new byte[64 * 1024];
    private int _count; // _buffer[0.._count)에 유효 데이터

    public event Action<byte[]> OnFrame = delegate { };

    // 소켓에서 읽은 data를 누적 버퍼에 이어붙이고 완결 프레임을 처리한다.
    public void OnReceive(ReadOnlySpan<byte> data)
    {
        // (B) 누적 버퍼 뒤에 이어붙임
        data.CopyTo(_buffer.AsSpan(_count));
        _count += data.Length;

        int offset = 0;
        while (_count - offset >= 2)
        {
            int len = BitConverter.ToUInt16(_buffer.AsSpan(offset, 2));
            if (_count - offset - 2 < len)
                break; // payload가 아직 덜 왔다 → 다음 수신까지 대기

            var frame = _buffer.AsSpan(offset + 2, len).ToArray();
            OnFrame(frame);
            offset += 2 + len;
        }

        // (A) 이번에 처리하고 남은 바이트 정리
        _count = 0;
    }
}
내 리뷰 · C#
내 답안 · 자동 저장

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