Infra & Security Eng/Network & Security
rdt 2.2 완벽 정리: NAK 없는 신뢰적 데이터 전송과 중복 ACK 메커니즘
by 엔지니어 E
2026. 2. 11.
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)
(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)
(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)
결과 : 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번 패킷 대기 )로 돌아감