1. TCP 길이 프리픽스 패킷 수신 루프

난이도 하 해설 보기 →

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

결함 코드 · C#
// ============================================================================
// [코드리뷰 문제] C# - TCP 길이 프리픽스 패킷 수신 루프
// ----------------------------------------------------------------------------
// 시나리오:
//   - 게임 클라이언트와 TCP 로 연결된 세션이다.
//   - 모든 패킷은 [2바이트 길이(payload 크기, little-endian)] + [payload] 형식.
//   - 비동기 Receive 콜백에서 들어온 바이트를 누적 버퍼에 모으고,
//     완성된 패킷을 하나씩 잘라 OnPacket 으로 넘긴다.
//   - 한 번의 Receive 콜백에 패킷이 0개, 1개, 여러 개, 혹은 "패킷의 일부"만
//     도착할 수 있다(TCP 는 스트림이라 메시지 경계가 없다).
//
// 요구사항:
//   - 부분 수신/복수 수신을 모두 올바르게 처리해야 한다.
//   - 처리량이 중요하므로 불필요한 복사는 피하고 싶다.
//
// 과제:
//   이 코드의 잠재적 문제를 모두 찾고, 왜/어떻게 발생하는지 설명하고,
//   수정안과 더 나은 설계를 제시하라.
//   (먼저 직접 리뷰한 뒤 answer.md 와 대조할 것)
// ============================================================================

using System;

public class PacketSession
{
    // 누적 버퍼와 현재 쌓인 바이트 수
    private readonly byte[] _buffer = new byte[4096];
    private int _writePos = 0;

    // 소켓 Receive 콜백이 호출하는 진입점.
    // data[0..len) 에 이번에 도착한 바이트가 들어있다.
    public void OnReceive(byte[] data, int len)
    {
        // (A) 도착한 바이트를 누적 버퍼 뒤에 이어붙인다.
        Array.Copy(data, 0, _buffer, _writePos, len);
        _writePos += len;

        int readPos = 0;

        // 버퍼에 완성된 패킷이 있는 동안 계속 잘라낸다.
        while (true)
        {
            // 길이 헤더(2바이트)가 아직 안 들어왔으면 대기
            if (_writePos - readPos < 2)
                break;

            // (B) payload 길이 읽기 (little-endian)
            ushort payloadLen = (ushort)(_buffer[readPos] | (_buffer[readPos + 1] << 8));

            // (C) payload 전체가 도착했는지 확인
            if (_writePos - readPos < 2 + payloadLen)
                break;

            // payload 구간을 잘라 핸들러로 전달
            int payloadStart = readPos + 2;
            OnPacket(_buffer, payloadStart, payloadLen);

            // 다음 패킷으로 이동
            readPos += 2 + payloadLen;
        }

        // (D) 처리하고 남은(미완성) 바이트를 버퍼 앞으로 당긴다.
        int remain = _writePos - readPos;
        Array.Copy(_buffer, readPos, _buffer, 0, remain);
        _writePos = remain;
    }

    private void OnPacket(byte[] buffer, int offset, int count)
    {
        // 패킷 디스패치 (생략)
    }
}
내 리뷰 · C#
내 답안 · 자동 저장

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