RDT(Reliable Data Transfer): 데이터를 안정적으로 전송하고 데이터의 무결성 및 전송 순서를 보장하는 메커니즘
RDT interface
- rdt_send(): 상위 계층에서 보낼 데이터가 있을 경우 호출
→ sender 호출- udt_send(): 신뢰할 수 없는 하위 계층으로 데이터를 전송할 때 호출
→ sender 호출- rdt_rcv(): 하위 계층에서 보낼 데이터가 있을 경우 호출
→ receiver 호출- deliver_data() : 상위 계층으로 데이터를 전송할 때 호출
→ receiver 호출
FSM(Finite state machine) : 어떤 상태가 어떤 이벤트에 의해 다른 상태로 변하는 것을 도식화 한 모델이며, RDT의 동작과정을 이해하기 위해 유한 상태 모델로 표현할 것이다.
모든 채널이 완벽하게 신뢰할 수 있다고 가정하며, 오류 검증 및 재전송 과정을 거치지 않고 단순 패킷 송수신만이 이루어진다.
→ sender와 receiver는 데이터의 송수신만 신경쓰게 된다.
Sender : rdt_send() 이벤트 발생 → 패킷 생성 → udt_send()
Receiver : rdt_rcv() 이벤트 발생 → 패킷 추출 → deliver_data()
실제로는 전송과정, 채널 등에서 오류가 발생한다.
RDT 2.0은 패킷 전송 중에 발생할 수 있는 비트 오류나 다른 오류를 감지하고 복구하기 위한 기능을 포함한다.
패킷의 무결성을 확인하기 위해 checksum 필드를 사용과 같은 에러 처리 메커니즘을 사용한다.
Receiver: 아래 응답 중 한가지를 sender에게 전송한다.
- 판별 결과 데이터 오류 : acknowledgement(ACK)
- 판별 결과 데이터에 오류 없음 : negative acknowledgement(NAK)
→ retransmit
경우 1: rdt_send() → 패킷 생성 → udt_send() → Wait for ACK or NAK → rdt_rcv() → 오류가 없으면 패킷 추출 → deliver_data() → udt_send(ACK) to Sender → rdt_rcv() && ACK
→ sender는 receiver로부터 응답이 오기까지 대기(stop and wait 방식)
경우 2 : rdt_send() → 패킷 생성 → udt_send() → Wait for ACK or NAK → rdt_rcv() → 오류 검출(corrupt) → udt_send(NAK) → rdt_rcv() && NAK → udt_send() → Wait for ACK or NAK → rdt_rcv() → 오류가 없으면 패킷 추출 → deliver_data() → udt_send(ACK) to Sender → rdt_rcv() && ACK
한계: ACK/NAK 메시지에 오류가 발생할 수 있다.
→ 무작정 재전송을 하는 경우: 만약 receiver가 데이터를 잘 처리한 후 ACK을 보내고 다음 데이터를 기다리고 있는데 재전송이 오게되면, 의도했던 데이터가 아니므로 문제가 발생할 수 있다.
재전송 데이터와 본래 데이터를 구별하기 위해 sender 패킷에 sequence number를 포함해서 송신한다.
과정
- receiver는 0번 패킷에 대해서 잘 받고 ACK을 sender에게 전송 및 1번 패킷 대기
- ACK가 오류가 발생으로 sender는 ACK를 수신 못함
- 0번 패킷을 Retransmission
- receiver는 0번 패킷이 다시 수신하고 ACK 에러를 인지
→ 보낸 ACK가 전송과정에서 오류가 발생해서 재전송이 왔다고 인지하고 별도의 처리 없이 sender에게 ACK 전송
Sender
- CASE I: 0번 패킷 전송 → 응답 손상 or NAK 수신 → 0번 패킷 재전송
- CASE II: 0번 패킷 전송 → ACK 수신 → 1번 패킷 전송
Receiver
- 0번 패킷 정상적으로 수신 → ACK 전송 → 1번 패킷 대기 → 0번 패킷 수신 → 재전송 패킷을 인지하고 ACK 전송
RDT 2.1에서는 중복여부만을 판별하므로 0, 1 두 가지 숫자만 사용한다.
NAK-free protocol로써 receiver는 ACK 만을 사용하며 마지막으로 성공적으로 수신한 패킷의 번호를 포함시켜 전송한다.
과정
- Sender
- CASE I: 0번 패킷을 전송하고 1번을 수신 하게되면 0번 패킷 재전송
- CASE II: 0번 패킷을 전송하고 0번을 수신 하게되면 1번 패킷 전송
- Receiver
- CASE I: 1번 패킷 정상 수신시에 ACK(1, checksum)
- CASE II: 비정상적으로 수신시에 ACK(0, checksum)
전송한 패킷이 손실되었다면, Receiver는 알 수 없다.
Sender 또한 응답을 기다리는 상태가 될 것이다.
RDT 3.0에서는 time-out을 도입하여 일정 시간만큼 기다린 후에 응답이 돌아오지 않으면 재전송을 수행한다.
과정
- Sender
- CASE I: 패킷 전송과 동시에 start_timer → corrupt 또는 #1 수신시에 continue(time-out 되므로) → time-out → 재전송
- CASE II: 패킷 전송과 동시에 start_timer → non-corrupt && #0 수신 → 1번 패킷 전송
- Receiver
- CASE I: 1번 패킷 정상 수신시 stop timer & ACK(1, checksum)
- CASE II: 비정상적(timeout)으로 수신시에 ACK(0, checksum)
RDT 3.0 경우 4가지
- 정상 송수신
- Packet Loss
- ACK Loss
- Premature timeout
→ ACK가 전송사는 사이에 time-out 되는 경우에는, receiver가 squence number를 확인하여 재전송 패킷 여부를 판단할 수 있다.
stop-and-wait 한계: sender는 패킷을 전송한 후 응답이 올 때까지 기다리는 stop and wait 방식을 가지고 있다.
→ wait 시간동안 대역폭이 낭비된다.
t = Tx(L/R) + Tx(L/R) + 2Tp(RTT)
→ 패킷을 보내기 시작했을 시점에서 ACK를 받을 때까지의 시간으로, sender는 Tx(L/R)만큼만 일을하고 나머지는 기다린다.
즉, Tx / (2Tp + TX) = (L/R) / (L/R + RTT)가 rdt 3.0 performance 가 될 수 있다.
- RTT (2Tp) : 패킷이 전송 완료됐을 시점부터 패킷에 대한 응답이 도착할 때까지의 시간
→ Transmission delay(Tx) : 패킷이 전체가 전송 시작될 때까지 걸리는 시간 = 패킷의 길이 / Transmission rate = L/R
→ Propagation delay(Tp) : 데이터가 전송 매체를 통해 전파되는 동안 소요되는 시간
초기 RDT 3.0에서는 Idle RQ(Ready Queue)라는 기본적인 방식을 사용하여 하나의 패킷을 보낸 후 ACK를 기다린 다음 다음 패킷을 보내는 방식을 사용했다.
→ ACK를 기다리는 동안 통신이 중지되어 효율↓
RDT 3.0에서는 Pipeline 방식을 채택하였다.
Pipeline 방식을Continuous RQ(Ready Queue)를 사용함으로써 ACK를 기다리지 않고 여러 개의 패킷을 한 번에 보낸다.
→ 전송 지연↓, 성능↑