본문 바로가기
Infra & Security Eng/Network & Security

rdt 2.2 완벽 정리: NAK 없는 신뢰적 데이터 전송과 중복 ACK 메커니즘

by 엔지니어 E 2026. 2. 11.
반응형

제목 없음.jpg
0.08MB
제목 없음1.jpg
0.11MB

rdt 2.2: NAK가 없는 rdt의 핵심 원리

ACK만 사용: rdt 2.1과 달리 NAK를 사용하지 않고 오직 ACK만 사용
번호 붙은 ACK: 수신자는 NAK 대신, 마지막으로 성공적으로 받은 패킷의 번호를 담아 ACK를 보낸다
중복 ACK 활용: 송신자는 중복된 ACK(예: 0번을 기다리는데 또 0번 ACK가 옴)를 받으면, 다음 패킷(1번)이 제대로 전달되지 않았음을 눈치채고 재전송함

송신측

송신자가 처음 0번 데이터를 보낼 준비를 하는 단계

1단계: 0번 패킷 전송 (Wait for call 0 from above)

송신자가 처음 0번 데이터를 보낼 준비를 하는 단계
  • (1) 이벤트: rdt_send(data)
    • 상위 계층에서 보낼 데이터가 내려온다
  • (2) 액션 1: sndpkt = make_pkt(0, data, checksum)
    • 0번 번호를 붙여 패킷을 만든다
  • (3) 액션 2: udt_send(sndpkt)
    • 패킷을 전송한다

2단계: 0번 ACK 확인 (Wait for ACK 0)

패킷을 보낸 후, 수신자가 **"0번"**을 잘 받았다고 응답하는지 기다리는 단계이다
    • 상황 A: 응답이 깨졌거나 1번 ACK가 온 경우 (실패)
      • (4) 이벤트: rdt_rcv(rcvpkt) && (corrupt(rcvpkt) || isACK(rcvpkt, 1))
        • 응답을 받았는데 내용이 깨졌거나(corrupt), 0번이 아닌 이전 번호(1번)의 ACK가 도착한 경우
      • (5) 액션: udt_send(sndpkt)
        • 수신자가 아직 0번을 못 받았다는 뜻이므로, 0번 패킷을 다시 전송하고 이 상태(Wait for ACK 0)에 머문다
    • 상황 B: 0번 ACK가 제대로 온 경우 (성공)
      • (6) 이벤트: rdt_rcv(rcvpkt) && notcorrupt(rcvpkt) && isACK(rcvpkt, 0)
        • 응답이 깨지지 않았고, 정확히 **0번을 잘 받았다는 ACK(0)**가 도착한 경우 이다
      • (7) 액션: $\Lambda$ (Lambda)
        • 추가 동작 없이 성공으로 간주한다
      • 결과: 다음 단계인 1번 패킷을 기다리는 상태로 넘어간다

3단계: 1번 패킷 전송 (Wait for call 1 from above)

0번 패킷 전송을 무사히 마치고, 상위 계층으로부터 다음 데이터를 기다리는 상태
        • (8) 이벤트: rdt_send(data)
          • 상위 계층에서 보낼 새로운 데이터가 내려옴
        • (9) 액션 1: sndpkt = make_pkt(1, data, checksum)
          • 이번에는 1번 번호를 붙여 패킷을 만듦
        • (10) 액션 2: udt_send(sndpkt)
          • 패킷을 전송함
        • 결과: 1번 ACK를 기다리는 상태로 이동함

4단계: 1번 ACK 확인 (Wait for ACK 1)

수신자가 "1번" 패킷을 잘 받았다고 응답하는지 기다리는 단계

      • 상황 A: 응답이 깨졌거나 0번 ACK가 온 경우 (실패)
        • (11) 이벤트: rdt_rcv(rcvpkt) && (corrupt(rcvpkt) || isACK(rcvpkt, 0))
          • 응답이 깨졌거나, 1번이 아닌 이전 번호(0번)의 ACK가 온 경우입니다. 이는 수신자가 아직 1번을 제대로 못 받았음을 의미함
        • (12) 액션: udt_send(sndpkt)
          • 1번 패킷을 다시 전송하고 이 상태(Wait for ACK 1)에 머물며 재 기다림
      • 상황 B: 1번 ACK가 제대로 온 경우 (성공)
        • (13) 이벤트: rdt_rcv(rcvpkt) && notcorrupt(rcvpkt) && isACK(rcvpkt, 1)
          • 응답이 멀쩡하고, 정확히 **1번을 잘 받았다는 ACK(1)**가 도착한 경우
        • (14) 액션: $\Lambda$ (Lambda)
          • 추가 동작 없이 성공으로 간주
      • 결과: 모든 과정이 완료되어 다시 1단계(0번 패킷 대기) 상태로 돌아감 

 

송신측

수신측이 **0번 패킷을 기다리는 상태(Wait for 0 from below)**를 기준으로 설명한다

1단계: 패킷 수신 및 상태 확인 (Wait for 0 from below)

수신자는 송신자로부터 패킷이 오기를 기다린다
  • 상황 A: 패킷이 깨졌거나 1번 패킷(이전 패킷)이 온 경우 (실패)
    • (1) 이벤트: rdt_rcv(rcvpkt) && (corrupt(rcvpkt) || has_seq1(rcvpkt))
      • 패킷이 오는 도중 망가졌거나(corrupt), 내가 기다리는 0번이 아니라 이미 받았던 1번 패킷이 다시 온 상황이다
    • (2) 액션: udt_send(sndpkt)
      • 새로운 ACK를 만들지 않고, **가장 최근에 성공했던 1번 패킷에 대한 ACK(ACK 1)**를 다시 보낸다
    • 결과: 0번을 계속 기다려야 하므로 자기 자신의 상태로 돌아온다
  • 상황 B: 0번 패킷이 제대로 온 경우 (성공)
    • (3) 이벤트: rdt_rcv(rcvpkt) && notcorrupt(rcvpkt) && has_seq0(rcvpkt)
      • 패킷이 깨지지 않았고(notcorrupt), 기다리던 0번 패킷이 정확히 도착함
    • (4) 액션 1: extract(rcvpkt, data)
      • 패킷에서 실제 데이터를 추출함
    • (5) 액션 2: deliver_data(data)
      • 추출한 데이터를 상위 계층(앱)으로 전달함
    • (6) 액션 3: sndpkt = make_pkt(ACK0, chksum)
      • "0번을 잘 받았다"는 의미로 ACK 0 패킷을 새로 만듦
    • (7) 액션 4: udt_send(sndpkt)
      • 완성된 ACK 0 패킷을 송신자에게 보냅
결과: 0번 처리가 끝났으므로 다음 상태(1번 패킷을 기다리는 상태)로 넘어감

2단계: 1번 패킷 기다리기 (Wait for 1 from below)

0번 패킷 처리를 무사히 마치고, 이제 1번 패킷이 오기를 기다리는 상태
  • 상황 A: 패킷이 깨졌거나 0번 패킷(이전 패킷)이 온 경우 (실패)
    • (8) 이벤트: rdt_rcv(rcvpkt) && (corrupt(rcvpkt) || has_seq0(rcvpkt))
    • 내용: 패킷이 훼손되었거나, 이미 처리한 0번 패킷이 다시 온 상황
    • (9) 액션: udt_send(sndpkt) (가장 최근에 성공했던 ACK 0를 다시 보냄)
    • 결과: 1번을 계속 기다려야 하므로 자기 자신의 상태로 돌아옴
  • 상황 B: 1번 패킷이 제대로 온 경우 (성공)
    • (10) 이벤트: rdt_rcv(rcvpkt) && notcorrupt(rcvpkt) && has_seq1(rcvpkt)
    • 내용: 기다리던 1번 패킷이 깨지지 않고 정확히 도착함
    • (11) 액션: 데이터 추출 → 앱으로 전달 → ACK 1 패킷 생성 → 송신자에게 전송
    • 결과: 1번 처리가 끝났으므로 다시 처음 상태(0번 패킷 대기)로 돌아감