30. 순서 보장 채널 재정렬 버퍼: 무제한 버퍼링과 갭 정지 (C#)

난이도 상 해설 보기 →

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

결함 코드 · C#
// [시나리오] 순서 보장 채널의 수신 재정렬 버퍼 (서버-클라 / RUDP)
// 신뢰성·순서 보장 채널은 각 프레임에 시퀀스 번호(seq)를 붙여 보낸다.
// 네트워크가 순서를 뒤섞으므로, 수신 측은 아직 차례가 아닌 프레임을
// "재정렬 버퍼"에 담아 두었다가, 기대하는 seq(NextExpected)가 채워지면
// 그 지점부터 연속된 프레임을 순서대로 상위(App)로 전달한다.
//
// [요구사항]
//   - 상위에는 항상 빈틈 없는 오름차순 seq 로 전달한다.
//   - 악의적/비정상 피어가 보낸 트래픽으로 서버 메모리가 무한정 커지면 안 된다.
//   - 한 프레임의 유실이 채널을 영구히 멈추게 해서는 안 된다.
//
// [과제] OrderedChannel.OnReceive 를 검토하고, 순서 밖 프레임이 계속 들어오거나
//        중간 한 프레임이 오래 오지 않을 때 어떤 문제가 생기는지 원인과 수정안을
//        제시하라. 표시된 (A)(B) 지점에 주목하라.

using System;
using System.Collections.Generic;

interface IAppSink { void Deliver(int seq, byte[] payload); }

class OrderedChannel
{
    private int _nextExpected;                                   // 다음에 전달할 seq
    private readonly Dictionary<int, byte[]> _reorder = new();   // seq -> payload
    private readonly IAppSink _app;

    public OrderedChannel(IAppSink app) { _app = app; }

    // 수신 스레드에서 프레임 하나가 도착할 때마다 호출된다.
    public void OnReceive(int seq, byte[] payload)
    {
        if (seq < _nextExpected)
            return;                       // 이미 전달한 과거 seq → 폐기

        // (A)
        _reorder[seq] = payload;          // 아직 차례가 아니면 버퍼에 보관

        // (B)
        while (_reorder.TryGetValue(_nextExpected, out byte[] next))
        {
            _app.Deliver(_nextExpected, next);
            _reorder.Remove(_nextExpected);
            _nextExpected++;
        }
    }
}
내 리뷰 · C#
내 답안 · 자동 저장

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