일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |
Tags
- Github
- 게임 서버 아키텍처
- 그리디
- 트라이
- vector insert
- 그래프 탐색
- MySQL
- Next
- MongoDB
- 이분 탐색
- DP
- PROJECT
- html5
- Prisma
- map
- router
- pm2
- ERD
- branch
- ccw 알고리즘
- localstorage
- 백준 9527번
- 자바스크립트
- insomnia
- JavaScript
- HTTP
- string
- Express.js
- Keys
- trie
Archives
- Today
- Total
dh_0e
[Transport Layer] TCP (Transmission Control Protocol) Part III. 본문
Network Programming/Transport Layer
[Transport Layer] TCP (Transmission Control Protocol) Part III.
dh_0e 2025. 6. 4. 17:14Congestion Control
Congetsion Window (cwnd)
- 송신자의 윈도우 크기를 결정하는 요소로 두 가지 요인에 의해 결정됨
- 수신자가 광고한 윈도우 크기(rwnd)
- 수신자의 버퍼 공간에 따라 결정됨
- 네트워크 혼잡 상태(cwnd)
- 작은 값을 쓰다가 점점 키워감, segment가 loss가 나면 cwnd를 줄여서 설정
- 네트워크가 데이터를 처리할 수 있는 속도보다 송신 속도가 빠를 경우, 네트워크가 송신자에게 속도를 줄이라고 알림
- 수신자가 광고한 윈도우 크기(rwnd)
- 실제 송신 윈도우 크기 = min(rwnd, cwnd) / 대부분 rwnd > cwnd
Congestion Policy
Slow Start (느린 시작)
- 전송 속도를 느리게 시작하지만, treshold에 도달할 때까지 점점 빠르게 증가시킴
- Exponential Increase (지수 함수 증가)
- treshold(특정 임계값)에 도달하면, 증가 속도를 줄임(AI)
- 초기 cwnd는 1 MSS(Maximum Segment Size)로 시작함
- MSS: 연결 수립 시 정해지는 세그먼트 최대 크기
- 즉, 수신 확인(ACK)이 올 때마다 전송 속도를 지수적으로 증가시킴
Congestion Avoidance (혼잡 회피)
- 혼잡을 미리 방지하기 위한 단계
- 혼잡이 발생하기 전에 미리 속도를 늦추는 것이 목적
- Additive Increase(선형 방식)으로 cwnd를 증가시킴
- 즉, slow start보다 느리게 증가해서 혼잡 가능성을 낮춤
- Additive Increase의 동작 시점: cwnd가 Exponential Increase 중에 "Slow Start Treshold"에 도달하면
- >> Slow Start 중단 / Congestion Avoidance(Additive Increase) 단계 진입
- 전체 RTT 주기에 대해 cwnd를 1 MSS 만큼만 증가시킴
- 사실 1 ACK 당 소수점만큼 증가시키는 중
Congestion detection (혼잡 감지)
- 송신자가 세그먼트를 재전송해야 할 때 혼잡이 발생했다고 판단
- RTO timer가 time-out - 강한 Congestion detection
- 3개의 중복 ACK 발생 - 약한 Congestion detection
RTO time-out (Strong C.D)
- threshold를 현재 cwnd의 절반으로 설정
- cwnd를 1 MSS로 초기화
- Slow Start 단계로 다시 진입
Triple Duplicate ACK (Weak C.D)
- 하나의 세그먼트는 손실됐지만, 그 앞의 세그먼트들은 정상적으로 도착, 그 뒤의 세그먼트들 또한 일부 도착
- threshold를 현재 cwnd의 절반으로 설정
- cwnd를 threshold로(사실 그냥 절반으로 나눔) 설정
- Congestion Avoidance 단계로 진입
- cwnd가 8에서 16이 될 때 threshold 10보다 크므로 9, 10 이런 식으로 아닌가?
- 흠 TCP Tahoe, TCP Reno 방식이 있다는데 방식이 다 다른 건가 표준은 fast recovery를 사용해서 threshold + 3으로 설정한다는데 나중에 더 알아보자
TCP Congestion Control
혼잡 제어(Congestion Control)은 안정적인 네트워크 구축을 위해 필요한 기능이다. 인터넷을 비롯한 모든 네트워크는 하드웨어적 한계가 존재하므로 감당할 수 있는 용량이 정해져 있다. 이러한
dev-ws.tistory.com
TCP timers
Retransmission Timer
- TCP가 전송 큐의 첫번 째 세그먼트를 보낼 때 타이머 시작
- RTO 타이머는 연결당 하나 (세그먼트마다 따로 있는 게 아님)
- 타이머가 만료되면 첫 번째 세그먼트를 재전송하고, 타이머 재시작
- 하나 이상의 세그먼트가 누적 ACK로 확인되면 해당 세그먼트를 큐에서 제거
- 근데 첫번째 세그먼트만 ACK가 오고 다음 세그먼트들은 타이머를 안 쓰나 ?!?!
- 큐가 비면 타이머 정지
- 남아 있으면 타이머 재시작해서 나머지 세그먼트들도 파악
시각 | 동작 내용 | 타이머 상태
-------|---------------------------------------------|-------------------------------
0.0s | A 전송 (Seq 1~1000) | ✅ 타이머 시작 (A 기준)
0.1s | B 전송 (Seq 1001~2000) | 유지 중
0.2s | C 전송 (Seq 2001~3000) | 유지 중
1.0s | ACK 1001 도착 (A 수신됨) | 🔁 타이머 재시작 (B 기준)
1.8s | ACK 2001 도착 (B 수신됨) | 🔁 타이머 재시작 (C 기준)
2.5s | ACK 3001 도착 (C 수신됨) | 🛑 타이머 종료 (모두 확인됨)
RTT(Round-Trip Time)
- 세그먼트를 보내고, 해당 ACK를 받을 때까지 걸리는 시간
- RTTs는 Smoothed RTT
- 측정된 RTT 값을 기반으로 가중 평균 필터링을 한 값
- 노이즈를 줄이기 위한 목적
- RTTm은 Measured RTT
- 실제로 측정된 RTT
- (Init) RTTs=RTTm
- (Update) RTTs=(1-a) * RTTs + a * RTTm
- a는 과거와 현재의 가중치를 설정하는 값
- a가 커질수록 현재 비중이 올라감
- a가 작아질수록 과거 비중이 올라감
RTO(Retrensmission Timeout)
- 이름은 재전송 시간초과지만 본 의미는 "재전송하기 전까지 기다리는 시간 한계"
- RTT 측정값을 바탕으로 RTO 값을 설정함
- RTTd는 평균과의 편차값
- RTO = RTTs + 4 * RTTd
Karn's Algorithm
- RTT를 구할 때 TCP가 세그먼트를 전송한 뒤, 도착한 ACK가
원래 보낸 것에 대한 건지, 재전송한 것에 대한 건지 구분이 안 됨 - >> 재전송된 세그먼트의 RTT는 측정하지 않는다
- 정확한 RTT 측정이 불가능하므로 RTO 계산에 방해가 되지 않게 함
Exponential Backoff
- RTO가 expire 되면 세그먼트를 재전송할 때마다 RTO 값을 2배로 늘림
- 첫 번째 재전송: 1 x RTO
두 번째 재전송: 2 x RTO
세 번째 재전송: 4 x RTO
네 번째 재전송: 8 x RTO
...
- 첫 번째 재전송: 1 x RTO
- 재전송 횟수가 많을수록 기다리는 시간도 늘어남
Persistence Timer
수신자가 window size 0을 광고하면 송신자는 nonzero window size를 받을 때까지 데이터 전송을 멈춤
그 이후 수신자가 윈도우를 늘렸는데 ACK가 손실되면? 서로를 기다리는 Deadlock 발생
- 송신자가 수신자로부터 0 윈도우 광고를 받으면 Persistence Timer 시작
- 타이머가 만료되면, 송신자는 "Probe" 세그먼트 전송
- 1바이트의 새로운 데이터만 포함
- Sequence Number는 있지만 절대 확인되지 않음
- 수신자가 새로운 윈도우 크기를 다시 광고하게 만들기 위함
- Probe 세그먼트를 보낸 뒤에도 Persistence timer는 다시 켜지며 주기적으로 Probe를 보냄
Keepalive Timer
- 오랫동안 아무 통신도 없는 연결을 끊기 위해 사용 (주로 서버에서 활성화)
- 보통 TLS의 보안 메커니즘 관리에 유저 세션의 timer가 더 짧아서 먼저 끊김
- 서버가 클라이언트로부터 데이터를 일정 시간 동안 받지 못하면 keepalive timer 동작
- 일정 시간(일반적으로 2시간)이 지나면 서버는 Keepalive Probe를 보내고 일정 횟수 이상 응답이 없으면 연결 종료
TIME-WAIT Time
- MSL(Maximum Segment Lifetime): 일반적으로 60초가 기본값
- 연결 종료 시점에서
- 마지막 ACK를 재전송할 수 있는 시간 확보
- 중복된 세그먼트가 네트워크에 남아 있을 경우 대비
- TIME-WAIT 상태는 2 x MSL 만큼 유지
- 보통 먼저 FIN을 보낸 쪽에서 발생
- ex) 클라이언트가 서버에 접속해서 데이터를 주고받다가 ctrl+c로 프로세스를 강제 종료함
다음에 다시 서버를 같은 포트로 실행하려고 하면 에러 발생
>> 이전 연결이 아직 TIME-WAIT 상태로 남아 있어서, OS가 해당 포트를 재사용하지 못하게 막고 있기 때문
TCP Options
- TCP 헤더에는 최대 40 bytes까지 옵션 필드를 추가할 수 있음
- single-byte options, multiple-byte options로 나뉨
MSS (Maximum Segment Size)
- 수신 측이 한 번에 수용할 수 있는 최대 데이터 크기를 정하고 handshake 과정에서 알려줌
- 근데
segment 전체 크기가 아니라 data 부분만 의미- MSS = MTU(Maximum Transmission Unit) - (IP 헤더 + TCP 헤더)
- MTU에 대한 설명은 https://dh-0e.tistory.com/125
[Network Layer] IPv4 Datagrams
IntroductionIP(Internet Protocol)는 TCP/IP 프로토콜 스택의 네트워크 계층에서 사용되는 전송 메커니즘이다.IP는 비신뢰성(unreliable) 및 비연결성(connectionless) 특성을 가진 데이터그램 기반 프로토콜이다.B
dh-0e.tistory.com
- 정의하지 않으면 Default 값은 536 bytes
Window Scale Factor
- window size를 증가시키기 위해 사용
- TCP 헤더의 윈도우 필드가 16 bit면 최대 65,535 bytes까지만 표현이 가능했음
- 고속 네트워크나 대역폭-지연 곱이 큰 환경의 경우 부족함
- Window Scaling option 사용 시
윈도우 크기 = 실제 값(윈도우 필드에 적힌 window size) x $2^{window scale factor}$- ex) TCP 헤더 윈도우 필드 값: 16,384
Window Scale Factor: 3
→ 최종 윈도우 크기 = 16,384 × $2^3$ = 131,072 bytes (128KB)
- ex) TCP 헤더 윈도우 필드 값: 16,384
- handshake에만 사용 가능하며 이후 데이터 전송 중에는 변경 불가
Timestamp
- 총 10 bytes (비교적 큰 편)
- 연결을 시작할 때(handshake) 클라이언트가 SYN 세그먼트에 timestamp 옵션을 포함
- O: SYN+ACK에 timestamp 옵션을 포함해서 응답하면 양쪽 모두 timestamp 옵션 사용 가능
- X: 옵션을 포함하지 않으면 사용 안 함
- 정확하고 일관된 RTT 계산을 위한 보조 수단으로 wraparound sequence numbers 방지
Measuring RTT
- 모든 계산은 송신자(sender)의 시계를 기준으로 함
- 송신자와 수신자의 시계 동기화는 필요 없음
- 수신자가 유지하는 변수 2가지
- lastack: 마지막으로 보낸 ACK의 시퀀스 번호
- tsrecent: 가장 최근에 받은 timestamp 값 저장용 변수
- 가장 먼저 수신한 세그먼트가 새로운 데이터일 때(어차피 첫 번째 세그먼트만 RTT 계산)
>> 그 세그먼트의 timestamp 값을 tsrecent 변수에 저장함 - 이후 이 값을 활용해 송신 측이 RTT를 정확히 계산 가능
SACK-Permitted & SACK Options
SACK-Permitted
- SACK Permitted Option: 단순히 "나 SACK 쓸 수 있어요" 표시
- Handshake 중 SYN 단계에서만 허용됨
SACK Option
- SACK(Selective Acknowledgment): 손실되지 않은 데이터 범위를 명시적으로 알려서 송신자가 정확히 손실된 부분만 재전송할 수 있도록 돕는 기능
- 데이터 전송 중에만 사용 (Handshake 중에 SACK-Permitted 옵션을 서로 교환한 이후)
- SACK Option은 수신자가 받은 블록들의 범위를 리스트로 포함
- 송신자는 이를 보고 정확히 손실된 구간만 재전송 가능
- 데이터 전송 중 들어가는 SACK은 Kind: 5, Length: 2 + (8 x 블록 수)
- 블록 수(한 쌍)는 최대 4개까지 (각 블록이 8 bytes = 4 bytes 시작 + 4bytes 끝 바이트 번호)
- 각 4 bytes인 블록 2개가 한 쌍을 이뤄 시작과 끝 바이트 번호를 나타냄
- 사실 끝 바이트 번호는 실제로 받은 byte + 1 한 값
- 끝 번호 ex) 위 예시의 6001은 exclusive(미포함)
- 즉, 4001 ~ 6000까지 바이트가 정상 수신됨을 의미 >> 시퀀스 번호 표현 방식
- 위 예시에 시작과 끝을 나타내는 블록 수가 2개이므로 length = 2 + (8 bytes * 2) = 18, kind는 SACK이기 때문에 5 고정
'Network Programming > Transport Layer' 카테고리의 다른 글
[Transport Layer] TCP (Transmission Control Protocol) Part II. (0) | 2025.06.03 |
---|---|
[Transport Layer] TCP (Transmission Control Protocol) Part I. (1) | 2025.06.03 |
[Transport Layer] UDP (User Datagram Protocol) (0) | 2025.06.03 |
[Transport Layer] Introduction (0) | 2025.06.02 |