이번 챕터의 목표를 다시 확인하자
- transport layer services의 원리 이해:
- multiplexing, demultiplexing
- reliable data transfer
- flow control
- congestion control
- internet transport layer protocol 이해
- UDP: connectionless transport
- TCP: connection-oriented reliable transport
- TCP congestion control
rdt1.0: reliable data transfer over a reliable channel
- 하위 channel이 완벽하게 reliable하다고 가정 (no bit error, no packet loss)
- sender와 receiver의 FSM을 각각 그려보자
- sender는 underlying channel에 데이터를 보낸다.
- receiver는 underlying channel에서 데이터를 받는다.
rdt2.0: bit error는 있을 수 있는 channel
- underlying channel에서 packet 내부의 bit들이 flip될 수 있다.
- receiver는 이를 어떻게 해결할까? (retransmit)
- ACKs(Acknowledgements): receiver가 sender에게 packet을 잘 받았다고 말해줌
- NAKs(Negative ACKs): receiver가 sender에게 packet에 에러가 있다고 말해줌
- sender가 NAK을 받으면 packet을 다시 보낸다.
- Stop and wait: sender는 packet 하나 보내고, receiver의 response를 기다린다!
- 위의 람다는 아무것도 안한다는 뜻을 의미하며, corrupt는 방해됐음을 의미
- 그러나 이는 ACK과 NAK packet의 loss는 고려하지 않았다.
- 만약 이게 corrupted되면 sender는 receiver의 상황을 알 수가 없다.
- 단순히 재전송해도 안되는 게, packet이 복사될 수 있다!
- 즉, sender는 각 packet에 sequence number를 추가하고, 이를 보고 receiver가 pakcet을 discard할지 위 layer에 전달할지 결정한다.
rdt 2.1: sender, handling garbled ACK/NAKs
- rdt 2.0에 sequence number를 추가했다.
- ACK과 NAK에는 sequence number가 들어갈 필요가 없는데, Stop and Wait방식을 사용하기 때문.
Sender FSM
- Sender Flow
- Sender는 0번 packet을 보내고 ACK, NAK 0을 기다린다.
- NAK 0가 왔다면 0번 packet을 retransmit한다.
- ACK 0가 왔다면 다음 packet인 1을 전송할 수 있는 상태로 기다린다.
- 1번 packet을 보내고, ACK, NAK 1을 기다린다.
- ACK, NAK 1에 대한 reaction은 0번과 같다.
- 모든 패킷을 보낼때 까지 위 과정을 반복한다.
- sequence number는 0과 1이면 충분하다!
- Stop-and-wait 방식을 선택하기 때문에, ACK이나 NAK이 오기 전까진 packet을 보내지 않는다. (In-flight packet은 1개)
- Inflight Packet: Sender에서 보내졌지만 receiver가 받기 전인 packet
- packet이 중복인지 아닌지 판단하는 데는 0과 1이면 충분한 것.
- ACK/NAK의 corrupt 여부를 확인해야한다.
- sequence number 0, 1 packet 중 무엇을 기다릴지 기억해야하기 때문에 두 배의 state 필요
Receiver FSM
- Receiver Flow
- 0번 packet에 오류가 있으면 NAK 0를 보내고 state는 그대로
- 0번 packet에 오류가 없으면 ACK 0를 보내고 1번 packet wait로 상태 변경
- 1번 packet에 대한 reaction은 0번과 같다.
- 받은 packet이 중복인지 확인해야 한다.
- state는 기다리는 pakcet이 0번인지 1번인지를 나타냄
- 기억해라: receiver는 ACK/NAK이 송신자에게 제대로 갔는지 여부를 알 수 없다!
rdt2.2: A NAK-free protocol
- 2.1과 같은 기능을 갖지만, NAK 대신 receiver는 마지막으로 받은 packet에 대한 ACK을 보낸다.
- receiver는 ACK된 pakcet의 sequence number를 반드시 명시적으로 포함해야 한다.
- Sender의 duplicated ACK은 결과적으로 NAK과 같은 역할을 한다. (지금 packet을 재전송해라..)
- 앞으로 확인하겠지만, TCP는 NAK-free를 위해 이와 같은 방식을 사용한다.
- Example flow
- 0번 packet을 보내고 제대로 송신되어서 ACK 0을 받음
- 1번 packet을 보냈는데, receiver는 packet의 오류 발견, ACK 1이 아닌 ACK 0 재전송
- Sender는 (기대 중인)ACK 1이 아닌 ACK 0을 받았으므로, 1번 packet 재전송
rdt3.0: error와 loss가 모두 있을 수 있는 channel
- rdt2.0/2.1/2.2는 packet eror에는 대응할 수 있으나, ACK/NAK 및 Packet의 loss에 대해서는 대응할 수 없음 (애초에 packet loss가 없다고 상정하고 만들었으니까..)
- Sender는 reasonable한 시간동안만 ACK을 기다린다.
- 이 시간동안 ACK을 못 받으면 packet 다시보냄
- 만약 packet이 그냥 지연되고 있던거라면..
- retransmission은 duplicate되지만, 이는 sequence number로 handle할 수 있다
- receiver는 ACK될 packet의 sequence number를 지정해야만 한다.
- Timer가 너무 짧으면..
- 빠르게 loss에 대한 recover가 가능하다
- 그러나 네트워크에 중복된 packet이 너무 많이 전송된다. (오버헤드 증가)
- Timer가 너무 길면..
- 데이터 전송에 충분한 시간을 주기 때문에 중복된 패킷이 전송될 일이 적어짐
- 그러나 loss에 대한 반응이 느려짐...
- 정상적인 상황만 고려했을 때 Sender의 FSM
- duplicated ACK을 고려하지 않음.
- timeout 발생시 어떻게 할지 명시되지 않음
모든 상황을 고려한 Sender의 FSM
- duplicated ACK은 그냥 ignore -> 가만히 두면 Timeout에 의해서 처리됨
- Timeout시 packet을 다시 보내고 timer는 다시 켠다.
- above에서 1을 call하길 기다리는 상황에서는 receiver에서 오는 packet들을 받을 이유가 없기 때문에 (아마 garbage값) 그냥 ignore
모든 상황에 대한 flow
- rdt3.0의 가장 큰 문제점: ACK신호가 지연된다면, (d) 상황처럼 전송이 꼬이는 상황이 발생한다.
- 또한 데이터 하나를 보내고 ACK이 올 때까지 데이터를 보내지 않기 때문에 성능이 안좋음
Go-Back-N
Sender
- Sender는 한 번에 전송할 Packet의 개수(window size)를 정한다.
- buffer에 그 개수만큼 packet을 저장해서 전송
- buffer를 Window, buffer size를 Window size라고 한다.
- buffer의 시작점인 send_base와 다음에 보낼 packet의 번호인 next_seq_num을 갖는다.
- Cumulative ACK(n): sequence number n을 포함하는 지금까지의 모든 packet에 대한 ACK
- ACK(n)을 받으면 window를 n+1까지 이동한다.
- 가장 옛날 in-flight packet이 timer의 기준
- timeout(n): window에 있는 모든 sequence number n이상의 packet들 재전송
Receiver
- ACK-only: 해당 시점까지 제대로 받은 packet 중에서, 가장 높은 sequence number로 ACK을 보냄.
- duplicate ACK 발생 가능
- rcv_base만 기억하면 된다.
- out-of-order packet에 대해서는..
- 버리거나, buffer에 저장해두거나 구현에 따라서 달라짐.
- buffering할 수도 있고 안 할 수도 있음.
Action flow
- 아래 Timeout 발생시 window에 있는 모든 packet을 다시 보내느 모습을 확인할 수 있음.
- buffering하는 경우 3, 4, 5를 처리해줘야됨..
Selective repeat
- Go-Back-N의 비효율성을 해결하기 위한 방식
- receiver는 제대로 받은 모든 packet들에 대해서 개별적으로 ACK를 날림 (not cumulative)
- 상위 layer로의 최종적 in-order delivery를 위해 필요에 따라 packet을 buffering한다.
- Sender는 unACKed packet에 대해서 각각 timeout/retransmit 한다.
- sedner는 각 unACKed packet당 timer를 유지해줘야 한다.
- 그러나 timer는 OS에서 아주 귀중한 resource임...
- Sender window
- 연속인 sequence number들 (~N)
- 전송된, unACKed packet의 sequence number를 제한한다.
- ACK이 loss되어 timeout되는 경우 sender는 해당 packet만 retransmit
- receiver에게 잘 도달하면, 연속된 sequence number 중 가장 높은 수로 window 이동
Sender
- 만약 window에서 다음으로 가능한 sequence number라면 packet을 보낸다.
- timeout(n): packet n만 다시 보내고, timer restart
- [sendbase, sendbase+N]안의 ACK(n)이 오면, packet n이 받아졌음을 마킹한다.
- 만약 n이 가장 작은 unACKed packet이라면, window base를 다음 unACKed sequence number로 이동시킨다.
- 즉, sendbase는 UnACKed 된 packet 중 가장 작은 값.
Recevier
- Packet n이 [rcvbase, rcvbase+N-1]안에 있다면...
- ACK(n)을 보낸다.
- 순서가 바꼇다면, buffer에 저장
- 제 순서인게 왔다면, 위로 올려주고(deliver buffered), window를 다음 not-yet-received packet으로 옮겨준다.
- [rcvbase-N, rcvbase-1]안의 packet이 왔다면 ACK이 loss됐음을 의미하기 때문에 ACK(n)을 다시 보내줌.
- 다른 경우는 무시 (ACK packet이 loss된 경우. packet은 ignore하고 reACK(n))
- Go-Back-N보다 효율적으로 보이지만, 모든 unACKed packet에 timer가 있어야하기 때문에 overhead가 더 크다.
Action flow
- ack2가 도착하면 sender window가 한 번에 6까지 옮겨진다. (send_base가 6)
- Sender측의 sequence number가 0 1 2 3 0 1 2로 반복되어도, 0과 그 다음 0은 다른 0으로 취급할 수 있다.
- 그러나 만약 receiver에서 sequence number가 반복된다면? 0, 1, 2에 대한 ACK이 loss되어서 sender는 첫 번째 0 packet을 보내도, receiver 측에선 그걸 두 번째 0으로 생각할 수 있다!
- 즉, 새로운 0에 해당하는 packet이 들어왔다고 생각하는 것.
- 이를 막기 위해선 sequence number / 2 >= window size 여야만 한다.
SampleRTT
- segment 전송부터 ACK 수신까지의 시간을 측정
- retransmittion은 무시해야됨. ( retransmit하는 동안 ACK이 도착할 수 있으니까.. )
EstimatedRTT
- EstimatedRTT = ( 1 - a ) * previous_EstimatedRTT + a * current_SampleRTT
- exponential weighted moving average(간단히 이동평균)을 써서 계산
- 최근 값이 영향을 더 많이주고, 과거의 값은 점점 영향력이 떨어진다는 점이 포인트
- 보통 a값은 0.125정도를 준다.
TimeoutInterval
- EstimatedRTT에 safety margin을 더한 값.
- TimeoutInterval = EstimatedRTT + 4 * DevRTT
- DevRTT = (1-b) * DevRTT + b * |SampleRTT - EsitmatedRTT| (b는 보통 0.25)
- DevRTT는 EstimatedRTT에서 파생된 SampleRTT의 이동평균임
rwnd
field 안의 free buffer space 값을 전달한다.rwnd
받아 unACKed in-flight data의 총량을 제한한다. (window size 조절로써 제한)