Skip to content

필사 모드: [컴퓨터 네트워크] 10. TCP 완전 정복: 연결, 흐름제어, 혼잡제어

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
원문 렌더가 준비되기 전까지 텍스트 가이드로 표시합니다.

본 포스팅은 James Kurose, Keith Ross의 Computer Networking: A Top-Down Approach (6th Edition) 교재를 기반으로 정리한 내용입니다.

1. TCP 연결

1.1 TCP 연결의 특징

TCP 연결의 핵심 속성:

├── 연결 지향 (Connection-Oriented)

│ 데이터 전송 전에 반드시 연결 수립

├── 전이중 (Full-Duplex)

│ 양방향 동시 데이터 전송

├── 점대점 (Point-to-Point)

│ 정확히 하나의 송신자와 하나의 수신자

└── 바이트 스트림 서비스

메시지 경계 없이 연속된 바이트 흐름

1.2 3-Way Handshake

TCP 연결 수립 과정이다.

클라이언트 서버

| |

|── SYN (seq=client_isn) ──────>| 1단계: SYN

| |

|<── SYN+ACK ──────────────────| 2단계: SYN+ACK

| (seq=server_isn, |

| ack=client_isn+1) |

| |

|── ACK (ack=server_isn+1) ───>| 3단계: ACK

| (데이터 포함 가능) |

| |

각 단계 설명

1단계 - SYN:

- 클라이언트가 SYN 세그먼트 전송

- SYN 비트 = 1

- 초기 순서 번호(client_isn) 설정

- 데이터 없음

2단계 - SYN+ACK:

- 서버가 SYN+ACK 세그먼트 응답

- SYN 비트 = 1, ACK 비트 = 1

- 서버의 초기 순서 번호(server_isn) 설정

- 확인 번호 = client_isn + 1

3단계 - ACK:

- 클라이언트가 ACK 세그먼트 전송

- SYN 비트 = 0 (연결 수립 완료)

- 이 세그먼트부터 데이터 포함 가능

1.3 TCP 연결 종료 (4-Way Handshake)

클라이언트 서버

| |

|── FIN ───────────────────────>| 1단계

| |

|<── ACK ──────────────────────| 2단계

| |

|<── FIN ──────────────────────| 3단계

| |

|── ACK ───────────────────────>| 4단계

| |

| (TIME_WAIT: 30초 대기) |

| → 연결 완전 종료 |

> TIME_WAIT 상태: 마지막 ACK가 손실되었을 때 FIN 재전송에 대응하기 위해 일정 시간 대기한다.

2. TCP 세그먼트 구조

0 1 2 3

0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1

┌───────────────────────┬───────────────────────┐

│ 출발지 포트 (16) │ 목적지 포트 (16) │

├───────────────────────┴───────────────────────┤

│ 순서 번호 (32) │

├───────────────────────────────────────────────┤

│ 확인 번호 (32) │

├────────┬──────┬───────┬───────────────────────┤

│헤더길이 │미사용│플래그 │ 수신 윈도우 (16) │

│ (4) │ (6) │(6bits)│ │

├────────┴──────┴───────┼───────────────────────┤

│ 체크섬 (16) │ 긴급 포인터 (16) │

├───────────────────────┴───────────────────────┤

│ 옵션 (가변 길이) │

├───────────────────────────────────────────────┤

│ │

│ 데이터 (가변 길이) │

│ │

└───────────────────────────────────────────────┘

주요 필드

| 필드 | 크기 | 설명 |

| ----------- | ------- | --------------------------------- |

| 순서 번호 | 32 bits | 세그먼트 데이터의 첫 바이트 번호 |

| 확인 번호 | 32 bits | 기대하는 다음 바이트 번호 |

| 수신 윈도우 | 16 bits | 수신 가능한 바이트 수 (흐름 제어) |

| 헤더 길이 | 4 bits | TCP 헤더 길이 (4바이트 단위) |

| 플래그 비트 | 6 bits | SYN, ACK, FIN, RST, PSH, URG |

3. 순서 번호와 확인 번호

3.1 순서 번호 (Sequence Number)

세그먼트에 포함된 데이터의 **첫 번째 바이트의 바이트 스트림 번호**다.

예시: 500,000 바이트 파일, MSS = 1,000 바이트

세그먼트 1: seq = 0, 데이터 = 바이트 0~999

세그먼트 2: seq = 1000, 데이터 = 바이트 1000~1999

세그먼트 3: seq = 2000, 데이터 = 바이트 2000~2999

...

세그먼트 500: seq = 499000, 데이터 = 바이트 499000~499999

3.2 확인 번호 (Acknowledgment Number)

수신자가 **다음으로 기대하는 바이트 번호**다. 누적 확인(cumulative acknowledgment) 방식이다.

예시: 텔넷 세션에서 'C'를 입력

호스트 A 호스트 B

|── seq=42, ack=79, 'C' ───>|

| | 'C' 수신, 에코 응답

|<── seq=79, ack=43, 'C' ───|

| |

|── seq=43, ack=80 ──────── >| (ACK)

seq=42: A가 보내는 데이터의 42번째 바이트

ack=79: A가 B로부터 79번째 바이트를 기대

ack=43: B가 A로부터 43번째 바이트를 기대 (42번 수신 완료)

4. RTT 추정과 타임아웃

4.1 SampleRTT

실제 측정한 RTT 값이다. 세그먼트 전송 시점부터 ACK 수신 시점까지의 시간이다.

- 재전송된 세그먼트는 측정에서 제외

- SampleRTT는 변동이 크다

4.2 EstimatedRTT (지수 가중 이동 평균)

EstimatedRTT = (1 - alpha) * EstimatedRTT + alpha * SampleRTT

alpha = 0.125 (권장값)

→ 최근 측정값에 더 큰 가중치

→ SampleRTT의 급격한 변동을 완화

4.3 DevRTT (RTT 편차)

DevRTT = (1 - beta) * DevRTT + beta * |SampleRTT - EstimatedRTT|

beta = 0.25 (권장값)

4.4 타임아웃 간격

TimeoutInterval = EstimatedRTT + 4 * DevRTT

EstimatedRTT: 평균 RTT 추정

4 * DevRTT: 안전 마진 (변동성 고려)

RTT 추정 예시 (시간 경과에 따른 변화):

RTT

(ms)

^

│ * *

│ * * * * SampleRTT (변동 큼)

│ ** * * *

│ ___________*____ EstimatedRTT (안정적)

│ TimeoutInterval (상한선)

└──────────────────> 시간

5. TCP 신뢰적 데이터 전송

TCP는 IP의 비신뢰적 서비스 위에 신뢰적 전송을 구현한다.

5.1 TCP 송신자의 핵심 이벤트

이벤트 1: 상위 계층으로부터 데이터 수신

→ 세그먼트 생성, 순서 번호 부여

→ IP에 전달

→ 타이머가 실행 중이 아니면 시작

이벤트 2: 타이머 만료

→ 가장 오래된 미확인 세그먼트 재전송

→ 타이머 재시작

이벤트 3: ACK 수신

→ SendBase 업데이트 (누적 확인)

→ 아직 미확인 세그먼트가 있으면 타이머 재시작

5.2 TCP 재전송 시나리오

시나리오 1: ACK 손실

호스트 A 호스트 B

|── seq=92, 8바이트 ───>|

| |── ACK=100 (손실!)

| 타이머 만료 |

|── seq=92, 8바이트 ───>| (재전송)

|<── ACK=100 ───────── |

시나리오 2: 조기 타임아웃

호스트 A 호스트 B

|── seq=92, 8바이트 ───>|

|── seq=100, 20바이트 ─>|

| |── ACK=100

| 타이머 만료! |── ACK=120

| (ACK=100이 아직 도착 안 함)

|── seq=92, 8바이트 ───>| (불필요한 재전송)

|<── ACK=100 ───────── |

|<── ACK=120 ───────── | (누적 ACK로 자연 해결)

시나리오 3: 누적 ACK

호스트 A 호스트 B

|── seq=92, 8바이트 ───>|

|── seq=100, 20바이트 ─>|

| |── ACK=100 (손실!)

| |── ACK=120 (도착)

|<── ACK=120 ───────── |

ACK=120은 120 이전의 모든 바이트 확인

→ seq=92 패킷도 확인된 것!

→ 재전송 불필요

5.3 빠른 재전송 (Fast Retransmit)

타임아웃을 기다리지 않고, **3개의 중복 ACK**를 받으면 즉시 재전송한다.

호스트 A 호스트 B

|── seq=92 ────────────>| ACK=100

|── seq=100 ───────────>| (손실!)

|── seq=120 ───────────>| ACK=100 (중복 1)

|── seq=140 ───────────>| ACK=100 (중복 2)

|── seq=160 ───────────>| ACK=100 (중복 3)

| |

| 3개 중복 ACK 수신! |

| 타이머 만료 전에 즉시 재전송

|── seq=100 ───────────>| ACK=180 (누적 확인)

> 3개의 중복 ACK = 원래 ACK + 추가 3개 = 총 4번의 동일한 ACK

6. 흐름 제어 (Flow Control)

6.1 문제

송신자가 너무 빠르게 데이터를 보내면 **수신자의 버퍼가 넘칠** 수 있다.

수신 측 버퍼:

┌──────────────────────────────┐

│[데이터][데이터][ 빈 공간 ]│

└──────────────────────────────┘

│←── 사용 중 ──→│←── rwnd ────→│

수신 윈도우

6.2 수신 윈도우 (Receive Window)

TCP는 **수신 윈도우(`rwnd`)** 를 통해 흐름 제어를 수행한다.

rwnd = RcvBuffer - (LastByteRcvd - LastByteRead)

RcvBuffer: 수신 버퍼의 전체 크기

LastByteRcvd: 마지막으로 수신된 바이트 번호

LastByteRead: 상위 계층이 읽어간 마지막 바이트 번호

6.3 동작 방식

수신자: ACK에 rwnd 값을 포함하여 전송

ACK 세그먼트:

┌────────┬────────┐

│ ACK=N │ rwnd=X │ "N번째 바이트까지 받았고,

└────────┴────────┘ X 바이트만큼 더 받을 수 있어"

송신자: rwnd를 초과하지 않도록 전송량 제한

LastByteSent - LastByteAcked <= rwnd

rwnd가 줄어들면 → 전송 속도 감소

rwnd가 0이면 → 전송 중단 (단, 1바이트 프로브 패킷 전송)

rwnd = 0 일 때의 문제

문제: 수신자가 rwnd=0을 보낸 후 버퍼를 비워도,

송신자에게 알릴 방법이 없음 (보낼 데이터가 없으므로)

해결: 송신자가 주기적으로 1바이트 프로브(probe) 세그먼트 전송

→ 수신자가 현재 rwnd 값을 포함한 ACK로 응답

→ 빈 공간이 생기면 송신 재개

7. TCP 혼잡 제어 (Congestion Control)

7.1 혼잡이란

혼잡(Congestion):

네트워크 내 데이터 양이 네트워크 용량을 초과하는 상태

증상:

├── 패킷 손실 (라우터 버퍼 오버플로)

├── 긴 지연 (라우터 큐에서 대기)

└── 불필요한 재전송 (타임아웃으로 인한)

7.2 혼잡 제어 vs 흐름 제어

흐름 제어: 수신자 보호 (수신 버퍼 오버플로 방지)

→ rwnd로 제어

혼잡 제어: 네트워크 보호 (네트워크 과부하 방지)

→ cwnd(congestion window)로 제어

실제 전송량:

LastByteSent - LastByteAcked <= min(cwnd, rwnd)

7.3 AIMD (Additive Increase Multiplicative Decrease)

TCP 혼잡 제어의 기본 철학이다.

cwnd 조정 원칙:

패킷 손실 없음 (ACK 정상 수신):

→ cwnd 증가 (대역폭 탐색)

패킷 손실 발생 (타임아웃 또는 3중복 ACK):

→ cwnd 감소 (혼잡 완화)

"톱니 형태" 패턴:

cwnd

^

│ /\ /\ /\

│ / \ / \ / \

│ / \ / \ / \

│ / \/ \/ \

└──────────────────────────> 시간

7.4 슬로 스타트 (Slow Start)

연결 초기에 cwnd를 **지수적으로 증가**시킨다.

초기 cwnd = 1 MSS

각 ACK 수신 시: cwnd += 1 MSS

(한 RTT에 모든 ACK를 받으면 cwnd가 2배)

cwnd 변화:

RTT 1: cwnd = 1 MSS → 1개 세그먼트 전송

RTT 2: cwnd = 2 MSS → 2개 세그먼트 전송

RTT 3: cwnd = 4 MSS → 4개 세그먼트 전송

RTT 4: cwnd = 8 MSS → 8개 세그먼트 전송

...

지수적 증가: 1, 2, 4, 8, 16, 32, ...

슬로 스타트의 종료 조건

1. cwnd >= ssthresh (느린 시작 임계값) → 혼잡 회피로 전환

2. 타임아웃 발생 → ssthresh = cwnd/2, cwnd = 1 MSS, 슬로 스타트 재시작

3. 3개 중복 ACK → ssthresh = cwnd/2, cwnd = ssthresh + 3, 빠른 회복

7.5 혼잡 회피 (Congestion Avoidance)

cwnd가 ssthresh에 도달한 후 **선형적으로 증가**시킨다.

각 RTT마다: cwnd += 1 MSS

(ACK 하나당: cwnd += MSS * MSS / cwnd)

cwnd 변화 (MSS 단위):

RTT n: cwnd = 10

RTT n+1: cwnd = 11

RTT n+2: cwnd = 12

...

선형 증가: 10, 11, 12, 13, ...

혼잡 이벤트 시 동작

타임아웃 발생:

ssthresh = cwnd / 2

cwnd = 1 MSS

→ 슬로 스타트로 복귀

3개 중복 ACK:

ssthresh = cwnd / 2

cwnd = ssthresh + 3 MSS

→ 빠른 회복으로 전환

7.6 빠른 회복 (Fast Recovery)

3개의 중복 ACK를 받았을 때의 상태다. TCP Reno에서 도입되었다.

빠른 회복 동작:

1. 중복 ACK 수신할 때마다: cwnd += 1 MSS

2. 새 ACK 수신 (손실 복구 완료):

cwnd = ssthresh

→ 혼잡 회피로 전환

3. 타임아웃 발생:

ssthresh = cwnd / 2

cwnd = 1 MSS

→ 슬로 스타트로 복귀

7.7 TCP 혼잡 제어 전체 상태 다이어그램

┌─────────────┐

시작 ───────>│ 슬로 스타트 │

│ cwnd 지수 증가│

└──────┬──────┘

cwnd >= ssthresh

┌──────▼──────┐

┌────>│ 혼잡 회피 │<────┐

│ │ cwnd 선형 증가│ │

│ └──────┬──────┘ │

│ │ │

새 ACK 3중복 ACK 타임아웃

(복구완료) │ │

│ ┌──────▼──────┐ │

│ │ 빠른 회복 │ │

└─────│ cwnd 조정 │ │

└─────────────┘ │

│ │

타임아웃 │

└────────────┘

ssthresh=cwnd/2

cwnd=1 MSS

→ 슬로 스타트

7.8 TCP Tahoe vs TCP Reno

cwnd

^

│ *

│ * *

│ * * TCP Reno

│ * * /

│ * * *

│ * * * *

│ * ** *

│ * *

│ *

│ * TCP Tahoe: 항상 cwnd=1로 복귀

│ *

└─────────────────────────────> 시간

↑ ↑

손실1 손실2

| 이벤트 | TCP Tahoe | TCP Reno |

| --------- | ------------ | ------------------------- |

| 타임아웃 | cwnd = 1 MSS | cwnd = 1 MSS |

| 3중복 ACK | cwnd = 1 MSS | cwnd = cwnd/2 (빠른 회복) |

8. TCP 공정성 (Fairness)

8.1 공정성의 정의

용량 `R`인 병목 링크를 `K`개의 TCP 연결이 공유할 때, 각 연결이 `R/K`의 처리량을 얻는 것이 이상적이다.

8.2 TCP가 공정한 이유

두 연결이 대역폭 R을 공유하는 경우:

처리량2

^

│ ╲ 공정 지점

│ ╲ (R/2, R/2)

│ ╲ *

R │ ╲ / \

│ * *

│ / ╲ \

│ / * *

│ / / ╲ \

│ / / * * → 공정 지점으로 수렴

└──────────────────> 처리량1

0 R

AIMD가 공정 지점으로 수렴하는 과정:

1. 두 연결이 균등하게 cwnd 증가 (Additive Increase)

→ 45도 방향으로 이동 (총합 = R 선을 향해)

2. 손실 발생 시 각각 cwnd를 절반으로 (Multiplicative Decrease)

→ 원점 방향으로 이동

3. 반복하면 공정 지점(R/2, R/2)으로 수렴

8.3 공정성의 현실적 한계

UDP는 혼잡 제어를 하지 않음:

→ TCP가 양보한 대역폭을 UDP가 차지

→ TCP에 불공정

병렬 TCP 연결:

→ 하나의 애플리케이션이 여러 TCP 연결을 열면

→ 단일 연결 애플리케이션보다 더 많은 대역폭 차지

→ 예: 브라우저가 동시에 여러 연결로 웹 객체 다운로드

9. 정리

TCP 핵심 메커니즘 요약:

연결 관리:

├── 3-way handshake (SYN → SYN+ACK → ACK)

└── 4-way handshake 종료 (FIN → ACK → FIN → ACK)

신뢰적 전송:

├── 순서 번호 + 확인 번호 (누적 ACK)

├── 타이머 기반 재전송

├── 빠른 재전송 (3중복 ACK)

└── RTT 추정 (EWMA)

흐름 제어:

└── rwnd (수신 윈도우)로 수신자 보호

혼잡 제어:

├── 슬로 스타트: 지수적 증가

├── 혼잡 회피: 선형적 증가

├── 빠른 회복: 3중복 ACK 시 cwnd 절반

└── AIMD → 공정한 대역폭 공유

10. 확인 문제

1번 (SYN): 클라이언트가 연결을 요청하고 자신의 초기 순서 번호를 알린다.

2번 (SYN+ACK): 서버가 연결을 수락하고 자신의 초기 순서 번호를 알리며, 클라이언트의 순서 번호를 확인한다.

3번 (ACK): 클라이언트가 서버의 순서 번호를 확인한다.

이 과정을 통해 양측 모두 상대방의 초기 순서 번호를 확인하고, 연결 의사를 확인한다. 2번만으로는 서버가 보낸 SYN+ACK를 클라이언트가 수신했는지 서버가 알 수 없다.

- **흐름 제어**: **수신자**를 보호한다. 수신 버퍼가 넘치지 않도록 `rwnd`(수신 윈도우)를 사용하여 송신자의 전송량을 제한한다.

- **혼잡 제어**: **네트워크**를 보호한다. 네트워크가 과부하되지 않도록 `cwnd`(혼잡 윈도우)를 사용하여 송신자의 전송량을 제한한다.

실제 전송량은 `min(cwnd, rwnd)`에 의해 결정된다.

"느린 시작"이라는 이름은 초기 `cwnd`가 **1 MSS**로 매우 작게 시작한다는 데서 유래한다. TCP 이전의 프로토콜들은 연결 시작 시 허용된 최대 윈도우 크기로 바로 데이터를 쏟아부었는데, 이는 네트워크 혼잡을 유발했다. 슬로 스타트는 이에 비해 "느리게" 1 MSS부터 시작한다는 의미다. 물론 지수적 증가이므로 실제로는 빠르게 증가한다.

3중복 ACK는 특정 세그먼트만 손실되었지만 **그 이후의 세그먼트는 도착했다**는 의미다. 네트워크가 여전히 일부 패킷을 전달하고 있으므로 혼잡이 심각하지 않다고 판단하여 `cwnd`를 절반으로만 줄인다 (빠른 회복).

반면 타임아웃은 **아무 ACK도 오지 않는** 상황으로, 네트워크 혼잡이 심각하다고 판단하여 `cwnd`를 1 MSS로 초기화하고 슬로 스타트부터 다시 시작한다.

현재 단락 (1/352)

본 포스팅은 James Kurose, Keith Ross의 Computer Networking: A Top-Down Approach (6th Edition) 교재를 기반으로 정리한...

작성 글자: 0원문 글자: 8,015작성 단락: 0/352