RDT 2.2 동작 방식 정리
rdt 2.2의 동작 방식을 sender/receiver 상태, ACK0/ACK1, 중복 ACK, 손상 packet 처리, rdt 2.1과 rdt 3.0 차이까지 정리했습니다.
RDT 2.2 동작 방식 정리
rdt 2.2는 신뢰적 데이터 전송 원리에서 "bit error는 발생하지만 packet loss는 아직 고려하지 않는" 단계의 프로토콜이다. rdt 2.1은 ACK와 NAK를 함께 사용하지만, rdt 2.2는 NAK을 제거하고 sequence number가 붙은 ACK만으로 같은 문제를 처리한다.
핵심은 간단하다. receiver가 정상 packet을 받으면 해당 sequence number에 대한 ACK를 보낸다. receiver가 손상된 packet이나 기대하지 않은 sequence number를 받으면, 새 데이터를 application에 넘기지 않고 마지막으로 정상 처리한 packet에 대한 ACK를 다시 보낸다. sender는 잘못된 ACK 또는 손상된 ACK를 받으면 같은 packet을 재전송한다.
전제 조건
| 항목 | rdt 2.2에서의 가정 |
|---|---|
| packet corruption | 발생할 수 있다. checksum으로 감지한다. |
| packet loss | 아직 다루지 않는다. timeout과 timer는 rdt 3.0에서 본격적으로 등장한다. |
| sequence number | 0과 1을 번갈아 사용한다. Alternating bit protocol의 기본 형태다. |
| ACK | ACK0, ACK1처럼 sequence number를 포함한다. |
| NAK | 사용하지 않는다. 중복 ACK로 NAK 역할을 대신한다. |
rdt 2.1과 rdt 2.2의 차이
| 구분 | rdt 2.1 | rdt 2.2 |
|---|---|---|
| 오류 알림 | ACK 또는 NAK | ACK만 사용 |
| receiver가 손상 packet을 받았을 때 | NAK 전송 | 마지막 정상 packet의 ACK 재전송 |
| sender가 해석하는 방식 | NAK를 보면 재전송 | 기대한 ACK가 아니면 재전송 |
| 장점 | 동작이 직관적 | 제어 메시지를 ACK 하나로 단순화 |
Sender 상태
sender는 두 종류의 대기 상태를 반복한다. application에서 보낼 데이터를 기다리는 상태와, 이미 보낸 packet에 대한 ACK를 기다리는 상태다.
WAIT_DATA_0
event: rdt_send(data)
action:
sndpkt = make_pkt(seq=0, data, checksum)
udt_send(sndpkt)
next: WAIT_ACK_0
WAIT_ACK_0
event: rdt_rcv(rcvpkt) and notcorrupt(rcvpkt) and isACK(rcvpkt, 0)
action:
none
next: WAIT_DATA_1
WAIT_ACK_0
event: rdt_rcv(rcvpkt) and (corrupt(rcvpkt) or isACK(rcvpkt, 1))
action:
udt_send(sndpkt)
next: WAIT_ACK_0seq=1도 같은 구조다. ACK1을 제대로 받으면 다음에는 seq=0 데이터를 보낼 준비 상태로 돌아간다.
WAIT_DATA_1
event: rdt_send(data)
action:
sndpkt = make_pkt(seq=1, data, checksum)
udt_send(sndpkt)
next: WAIT_ACK_1
WAIT_ACK_1
event: rdt_rcv(rcvpkt) and notcorrupt(rcvpkt) and isACK(rcvpkt, 1)
action:
none
next: WAIT_DATA_0
WAIT_ACK_1
event: rdt_rcv(rcvpkt) and (corrupt(rcvpkt) or isACK(rcvpkt, 0))
action:
udt_send(sndpkt)
next: WAIT_ACK_1Receiver 상태
receiver는 다음에 받을 sequence number를 기준으로 상태를 가진다. WAIT_SEQ_0 상태에서는 seq0 packet만 application에 넘긴다. seq1이 오면 중복 또는 순서 오류로 보고 마지막 ACK를 다시 보낸다.
WAIT_SEQ_0
event: rdt_rcv(rcvpkt) and notcorrupt(rcvpkt) and has_seq(rcvpkt, 0)
action:
extract(rcvpkt, data)
deliver_data(data)
sndpkt = make_pkt(ACK0, checksum)
udt_send(sndpkt)
next: WAIT_SEQ_1
WAIT_SEQ_0
event: rdt_rcv(rcvpkt) and (corrupt(rcvpkt) or has_seq(rcvpkt, 1))
action:
udt_send(last ACK1)
next: WAIT_SEQ_0WAIT_SEQ_1
event: rdt_rcv(rcvpkt) and notcorrupt(rcvpkt) and has_seq(rcvpkt, 1)
action:
extract(rcvpkt, data)
deliver_data(data)
sndpkt = make_pkt(ACK1, checksum)
udt_send(sndpkt)
next: WAIT_SEQ_0
WAIT_SEQ_1
event: rdt_rcv(rcvpkt) and (corrupt(rcvpkt) or has_seq(rcvpkt, 0))
action:
udt_send(last ACK0)
next: WAIT_SEQ_1정상 흐름: seq0 전송
- sender가 application에서 data를 받는다.
- sender가
seq0, data, checksum을 포함한 packet을 만든다. - sender가 packet을 unreliable channel로 보낸 뒤
ACK0을 기다린다. - receiver가 손상되지 않은
seq0packet을 받는다. - receiver가 data를 추출해서 application에 전달한다.
- receiver가
ACK0을 만든 뒤 sender에게 보낸다. - sender가 정상
ACK0을 받으면 다음 데이터는seq1로 보낼 준비 상태가 된다.
손상된 data packet 처리
receiver가 WAIT_SEQ_0 상태에서 손상된 packet을 받으면 data를 application에 넘기면 안 된다. 이때 rdt 2.2는 NAK을 보내지 않고, "내가 마지막으로 정상 처리한 것은 seq1이었다"는 의미의 ACK1을 다시 보낸다. sender는 지금 ACK0을 기다리는 중인데 ACK1을 받았으므로 seq0 packet이 정상 처리되지 않았다고 판단하고 같은 packet을 다시 보낸다.
sender: WAIT_ACK_0
receiver: WAIT_SEQ_0
data packet seq0 is corrupted
receiver sends duplicate ACK1
sender receives ACK1 while waiting ACK0
sender retransmits seq0손상된 ACK 처리
이번에는 data packet은 정상 도착했지만 ACK가 손상된 경우다. receiver는 data를 application에 이미 넘기고 WAIT_SEQ_1 상태로 이동했다. sender는 ACK를 해석할 수 없으므로 기존 seq0 packet을 재전송한다. receiver는 WAIT_SEQ_1 상태에서 seq0을 다시 받았으므로 중복으로 판단하고 data를 다시 전달하지 않는다. 대신 ACK0을 다시 보낸다.
sender sends seq0
receiver delivers seq0 and sends ACK0
ACK0 is corrupted
sender retransmits seq0
receiver sees duplicate seq0
receiver does not deliver data again
receiver sends ACK0 again중복 packet을 application에 넘기지 않는 이유
신뢰적 전송에서 중요한 것은 "빠짐없이 전달"뿐 아니라 "중복 전달 방지"다. ACK가 손상되면 sender는 같은 packet을 다시 보낼 수 있다. receiver가 sequence number를 확인하지 않고 application에 매번 넘기면 같은 데이터가 두 번 처리된다. 결제, 파일 쓰기, 메시지 큐 같은 시스템에서는 중복 처리가 심각한 장애가 될 수 있다. 그래서 rdt 2.2는 sequence number를 사용해 중복 packet을 식별하고, 중복이면 ACK만 다시 보낸다.
rdt 2.2가 아직 해결하지 못한 것
rdt 2.2는 packet 손상에는 대응하지만 packet loss에는 대응하지 못한다. data packet 자체가 사라지거나 ACK가 완전히 사라지면 sender는 계속 ACK를 기다리게 된다. 이 문제를 해결하려면 timer와 timeout 기반 재전송이 필요하고, 그것이 rdt 3.0에서 추가되는 핵심이다.
요약
rdt 2.2는 NAK을 제거하고 ACK만 사용한다.- ACK에는
ACK0,ACK1처럼 sequence number가 들어간다. - receiver는 손상 packet 또는 기대하지 않은 sequence를 받으면 마지막 정상 ACK를 다시 보낸다.
- sender는 기대한 ACK가 아니거나 ACK가 손상되면 마지막 packet을 재전송한다.
- sequence number는 중복 packet이 application에 중복 전달되는 것을 막는다.
- loss를 처리하려면 timer가 필요하므로 rdt 3.0으로 넘어가야 한다.