9. C# half-open 연결 감지: 단방향 경로 장애와 송신 결과 처리

난이도 상 해설 보기 →

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

결함 코드 · C#
// ============================================================================
// [코드리뷰 문제] C# - half-open 연결 감지: 단방향 경로 장애와 송신 결과 처리
// ----------------------------------------------------------------------------
// 시나리오:
//   - 실시간 대전 서버(비동기 소켓). 서버는 매 틱 상태 스냅샷을 각 세션에
//     비동기 송신(SendAsync)한다. 클라는 입력을 올려보낸다.
//   - 모바일/와이파이 환경에서 "단방향 경로 장애"가 발생한다: 서버→클라
//     방향만 죽고(패킷이 블랙홀로 빠짐), 클라→서버는 잠시 살아있거나 그 반대.
//     또는 클라 단말이 갑자기 사라져 FIN/RST 가 끝내 오지 않는다(half-open).
//   - 송신(틱) 스레드와 수신 완료 콜백이 같은 세션을 동시에 만진다.
//
// 요구사항:
//   - half-open / 단방향 장애를 수십 초 내에 감지해 세션을 정리한다.
//   - 송신이 실제로 상대에게 도달하는지(또는 막혔는지)를 근거로 판정한다.
//   - 살아있는 정상 세션을 오인 끊김 시키지 않는다.
//
// 과제:
//   이 코드의 잠재적 문제를 모두 찾고, 왜 문제인지 설명하고,
//   수정안과 더 나은 설계를 제시하라.
//   (먼저 직접 리뷰를 적은 뒤 answer.md 와 대조할 것)
// ============================================================================

using System;
using System.Net.Sockets;
using System.Threading.Tasks;

public sealed class Conn
{
    private readonly Socket _socket;
    public volatile bool Closed = false;

    // (A) 마지막으로 "송신을 시도한" 시각 (수신 시각이 아님에 유의)
    public DateTime LastSendAttempt = DateTime.Now;

    public Conn(Socket socket) { _socket = socket; }

    // 매 틱 호출: 상태 스냅샷을 비동기 송신
    public void SendSnapshot(byte[] data)
    {
        if (Closed) return;

        LastSendAttempt = DateTime.Now;

        // 비동기 송신. 반환값/완료결과를 확인하지 않는다. (B)
        _ = _socket.SendAsync(data, SocketFlags.None);
    }

    // 수신 완료 콜백
    public void OnRecv(byte[] data, int len)
    {
        if (len <= 0) { Close(); return; }
        // 클라 입력 처리 ...
        // (C) 수신했다는 사실만으로 "연결 살아있음"으로 간주
    }

    // (D) 죽음 판정: 별도 워치독 스레드가 주기적으로 호출
    //     "오랫동안 송신을 시도하지 않았으면" 죽었다고 본다.
    public bool LooksDead(TimeSpan idleLimit)
    {
        var now = DateTime.Now;
        return (now - LastSendAttempt) > idleLimit;   // (E)
    }

    public void Close()
    {
        if (Closed) return;
        Closed = true;
        // _socket.Close() ...
    }
}
내 리뷰 · C#
내 답안 · 자동 저장

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