
TCP는 패킷이 아니라 byte stream을 세는 점이 앞서 본 rdt와 다릅니다.
| 필드 | 값의 의미 |
|---|---|
| sequence number | 이 세그먼트의 첫 바이트가 전체 스트림에서 몇 번째인가 |
| acknowledgment number | 상대에게서 다음에 받기를 기대하는 바이트 번호 |
예를 들어 sequence number 1000인 세그먼트에 500바이트가 실려 있으면, 수신 측은 acknowledgment number 1500을 돌려줍니다. "1499번까지 다 받았고 다음은 1500번"이라는 뜻입니다. cumulative ACK가 바이트 단위로 구현된 형태입니다.
full duplex이므로 ACK는 별도 세그먼트가 아니어도 됩니다. 보낼 데이터가 있으면 그 세그먼트 헤더의 acknowledgment number에 얹어 보냅니다.
타이머 값은 크게 잡아도 작게 잡아도 손해입니다. 짧으면 멀쩡한 세그먼트를 다시 보내고, 길면 진짜 손실에서 복구가 느려집니다. 기준은 RTT여야 하는데, RTT는 경로와 혼잡도에 따라 계속 변합니다.
그래서 TCP는 측정한 값 하나를 그대로 쓰지 않고 EstimatedRTT(추정 RTT)를 유지합니다. 새 측정값이 들어올 때마다 기존 추정치를 조금씩 갱신하는 지수 가중 이동평균입니다.
ALPHA, BETA = 0.125, 0.25
def update(estimated_rtt, dev_rtt, sample_rtt):
dev_rtt = (1 - BETA) * dev_rtt + BETA * abs(sample_rtt - estimated_rtt)
estimated_rtt = (1 - ALPHA) * estimated_rtt + ALPHA * sample_rtt
timeout = estimated_rtt + 4 * dev_rtt
return estimated_rtt, dev_rtt, timeout
α가 0.125이므로 새 측정값은 8분의 1만 반영됩니다. 한 번 튄 값에 타이머가 요동치지 않게 하려는 것입니다.
그런데 평균만으로는 부족합니다. RTT가 들쭉날쭉한 경로라면 평균 근처에 타이머를 두면 자주 헛발질합니다. 그래서 변동폭 DevRTT를 따로 추정해 안전 마진으로 더합니다. 최종 식은 EstimatedRTT + 4 × DevRTT입니다. RFC 6298은 α를 1/8, β를 1/4로 쓰도록 하고, 측정값이 하나도 없는 초기에는 타이머를 1초로 두도록 권합니다.
두 가지 예외가 더 있습니다. timeout이 발생하면 다음 타이머 값을 이전의 두 배로 늘립니다. 또 재전송한 세그먼트에 대해서는 RTT를 측정하지 않습니다. 돌아온 ACK가 원본에 대한 것인지 재전송분에 대한 것인지 알 수 없어 값이 오염되기 때문입니다.
selective repeat은 세그먼트마다 타이머를 하나씩 두었지만, TCP 구현은 타이머를 하나만 씁니다. 가장 오래된 미확인 세그먼트에 대해서만 재는 것입니다. 타이머 수십 개를 관리하는 비용을 피하는 현실적 타협입니다.

두 번째 시나리오가 cumulative ACK의 이점입니다. ACK 하나가 사라져도 뒤따르는 ACK가 앞을 포함하므로 재전송이 일어나지 않습니다.
timeout을 기다리는 것은 느립니다. 타이머는 안전 마진까지 더해 잡혀 있으니, 손실 하나 때문에 수백 밀리초를 그냥 흘려보내게 됩니다.
단서는 duplicate ACK(중복 ACK)입니다. 수신 측은 중간이 비면 계속 같은 acknowledgment number를 돌려보냅니다. 송신 측이 같은 ACK를 반복해서 받는다는 것은, 뒤의 세그먼트들은 도착하고 있는데 중간 하나가 비었다는 신호입니다.

기준은 중복 ACK 3개입니다. 왜 하필 셋인가 하면, 단순히 순서가 뒤바뀌어 도착한 경우에도 중복 ACK가 한두 개는 생기기 때문입니다. 세 개 이상 연달아 오면 재정렬이 아니라 손실이라고 보는 것이 타당하다는 경험칙입니다. 이때 타이머 만료를 기다리지 않고 바로 재전송하는 것이 fast retransmit(빠른 재전송)입니다.
이름이 비슷해 헷갈리지만 막으려는 대상이 다릅니다.
| flow control | congestion control | |
|---|---|---|
| 누가 제한하나 | 수신 측이 window 필드로 알림 | 송신 측이 스스로 추정해 조절 |
| 무엇을 보호 | 수신 측 버퍼 | 네트워크 내부의 라우터 큐 |
| 신호 | 상대가 알려주는 남은 버퍼 크기 | 손실과 중복 ACK |
| 위험 | 받는 쪽이 못 따라가 버퍼 넘침 | 코어가 붐벼 패킷이 버려짐 |
flow control은 상대가 감당할 수 있는 만큼만 보내는 장치입니다. 수신 측은 자기 버퍼의 남은 공간을 헤더의 window 필드에 담아 매번 알려주고, 송신 측은 미확인 데이터가 그 값을 넘지 않게 유지합니다. 반면 congestion control은 아무도 알려주지 않는 상태를 스스로 짐작해야 하는 문제입니다.