일련번호와 확인 응답 번호의 구조
일련번호와 확인 응답 번호의 구조
1. 일련번호와 확인 응답 번호란?
개념
┌─────────────────────────────────────────────────────────────┐
│ 일련번호와 확인 응답 번호 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 3-Way Handshake 완료 후, 실제 데이터를 주고받을 때 │
│ TCP 헤더의 두 가지 번호가 핵심 역할을 한다: │
│ │
│ 1. 일련번호 (Sequence Number) │
│ ───────────────────────────────────────── │
│ • 송신측이 "이 데이터가 몇 번째인지" 알려줌 │
│ • 데이터의 순서를 표시 │
│ • 32비트 (약 42억까지 표현 가능) │
│ │
│ 2. 확인 응답 번호 (Acknowledgment Number) │
│ ───────────────────────────────────────── │
│ • 수신측이 "여기까지 받았으니 다음 거 보내줘" 알려줌 │
│ • 다음에 받기 원하는 데이터 번호 │
│ • ACK 플래그가 1일 때만 유효 │
│ │
│ │
│ 왜 필요한가? │
│ ───────────────────────────────────────── │
│ • TCP는 대용량 데이터를 분할해서 전송 │
│ • 네트워크에서 패킷 순서가 뒤바뀔 수 있음 │
│ • 패킷이 손실될 수 있음 │
│ → 번호로 순서 보장 + 손실 감지 + 재전송 │
│ │
└─────────────────────────────────────────────────────────────┘TCP 헤더에서의 위치
┌─────────────────────────────────────────────────────────────┐
│ TCP 헤더 구조 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 0 16 31 │
│ ├────────────────────┼────────────────────┤ │
│ │ 출발지 포트 │ 목적지 포트 │ │
│ │ (16비트) │ (16비트) │ │
│ ├────────────────────┴────────────────────┤ │
│ │ ┌─────────────────────────────────────┐│ │
│ │ │ 일련번호 (Sequence Number) ││ ← 여기! │
│ │ │ (32비트) ││ │
│ │ └─────────────────────────────────────┘│ │
│ ├─────────────────────────────────────────┤ │
│ │ ┌─────────────────────────────────────┐│ │
│ │ │ 확인 응답 번호 (ACK Number) ││ ← 여기! │
│ │ │ (32비트) ││ │
│ │ └─────────────────────────────────────┘│ │
│ ├────────┬──────┬────┬────────────────────┤ │
│ │헤더길이│예약 │플래그│ 윈도우 크기 │ │
│ │ (4bit)│(6bit)│(6bit)│ (16비트) │ │
│ ├────────┴──────┴────┴────────────────────┤ │
│ │ 체크섬 │ 긴급 포인터 │ │
│ └────────────────┴────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘2. 일련번호 (Sequence Number) 상세
일련번호의 역할
┌─────────────────────────────────────────────────────────────┐
│ 일련번호 (Sequence Number) │
├─────────────────────────────────────────────────────────────┤
│ │
│ 정의: │
│ • 전송하는 데이터의 첫 번째 바이트 번호 │
│ • "이 세그먼트는 N번째 바이트부터 시작해요" │
│ │
│ │
│ 초기 일련번호 (ISN: Initial Sequence Number) │
│ ───────────────────────────────────────── │
│ • 연결 시작 시 랜덤하게 선택 │
│ • 0부터 시작하지 않음 (보안상 이유) │
│ • 3-Way Handshake에서 서로 교환 │
│ │
│ │
│ 예시: │
│ ───────────────────────────────────────── │
│ │
│ 원본 데이터: "Hello, World!" (13바이트) │
│ │
│ ISN = 1000 이라면: │
│ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ 바이트 위치: 1000 1001 1002 1003 1004 ... │ │
│ │ 데이터: H e l l o ... │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ Seq=1000 → "H"부터 시작하는 데이터 │
│ Seq=1005 → ", "부터 시작하는 데이터 │
│ │
└─────────────────────────────────────────────────────────────┘일련번호 증가 규칙
┌─────────────────────────────────────────────────────────────┐
│ 일련번호 계산 규칙 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 다음 Seq = 현재 Seq + 전송한 데이터 바이트 수 │
│ │
│ │
│ 예시: 1000바이트씩 3번 전송 │
│ ───────────────────────────────────────── │
│ │
│ 전송 1: Seq = 1000, 데이터 = 1000바이트 │
│ → 바이트 1000 ~ 1999 전송 │
│ │
│ 전송 2: Seq = 2000, 데이터 = 1000바이트 │
│ → 바이트 2000 ~ 2999 전송 │
│ │
│ 전송 3: Seq = 3000, 데이터 = 1000바이트 │
│ → 바이트 3000 ~ 3999 전송 │
│ │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Seq=1000 Seq=2000 Seq=3000 │ │
│ │ ┌────────┐ ┌────────┐ ┌────────┐ │ │
│ │ │ 1000B │ │ 1000B │ │ 1000B │ │ │
│ │ │데이터 1│ │데이터 2│ │데이터 3│ │ │
│ │ └────────┘ └────────┘ └────────┘ │ │
│ │ 1000-1999 2000-2999 3000-3999 │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ │
│ 특별한 경우: │
│ ───────────────────────────────────────── │
│ • SYN 패킷: Seq 1 소비 (데이터 없어도) │
│ • FIN 패킷: Seq 1 소비 (데이터 없어도) │
│ • ACK만 있는 패킷: Seq 소비 안 함 │
│ │
└─────────────────────────────────────────────────────────────┘3. 확인 응답 번호 (Acknowledgment Number) 상세
확인 응답 번호의 역할
┌─────────────────────────────────────────────────────────────┐
│ 확인 응답 번호 (Acknowledgment Number) │
├─────────────────────────────────────────────────────────────┤
│ │
│ 정의: │
│ • 수신측이 다음에 받기 원하는 바이트 번호 │
│ • "N번까지 잘 받았으니, N+1번부터 보내줘" │
│ │
│ │
│ 계산 공식: │
│ ───────────────────────────────────────── │
│ │
│ ACK Number = 받은 Seq + 받은 데이터 크기 │
│ │
│ │
│ 예시: │
│ ───────────────────────────────────────── │
│ │
│ 송신측: Seq=1000, 데이터=500바이트 전송 │
│ → 바이트 1000 ~ 1499 전송 │
│ │
│ 수신측: ACK=1500 응답 │
│ → "1500번부터 보내줘" (1000~1499는 잘 받았어) │
│ │
│ │
│ [송신측] [수신측] │
│ │ │ │
│ │ Seq=1000, Len=500 │ │
│ ├─────────────────────────────────→│ │
│ │ (바이트 1000~1499) │ │
│ │ │ │
│ │ ACK=1500 │ │
│ │←─────────────────────────────────┤ │
│ │ "1500번부터 보내줘!" │ │
│ │ │ │
│ │
└─────────────────────────────────────────────────────────────┘누적 확인 응답 (Cumulative ACK)
┌─────────────────────────────────────────────────────────────┐
│ 누적 확인 응답 │
├─────────────────────────────────────────────────────────────┤
│ │
│ TCP는 "누적 ACK" 방식 사용 │
│ → ACK=N은 "N-1번까지 모두 받았다"는 의미 │
│ │
│ │
│ 예시: 3개 세그먼트 연속 전송 │
│ ───────────────────────────────────────── │
│ │
│ [송신측] [수신측] │
│ │ │ │
│ │ Seq=1000, Len=100 │ │
│ ├────────────────────────────────────→│ ✓ 받음 │
│ │ │ │
│ │ Seq=1100, Len=100 │ │
│ ├────────────────────────────────────→│ ✓ 받음 │
│ │ │ │
│ │ Seq=1200, Len=100 │ │
│ ├────────────────────────────────────→│ ✓ 받음 │
│ │ │ │
│ │ ACK=1300 │ │
│ │←────────────────────────────────────┤ │
│ │ "1300번까지 모두 받았어!" │ │
│ │ (1000~1299 바이트 확인) │ │
│ │ │ │
│ │
│ │
│ 장점: │
│ • 모든 패킷마다 ACK 안 보내도 됨 → 효율적 │
│ • 하나의 ACK로 여러 세그먼트 확인 가능 │
│ │
└─────────────────────────────────────────────────────────────┘4. 데이터 전송 과정 예시
전체 통신 흐름
┌─────────────────────────────────────────────────────────────┐
│ 데이터 전송 전체 과정 │
├─────────────────────────────────────────────────────────────┤
│ │
│ [클라이언트] [서버] │
│ │
│ ═══════════ 1단계: 연결 설정 (3-Way Handshake) ═══════════ │
│ │ │ │
│ │ SYN, Seq=100 │ │
│ ├───────────────────────────────────────→│ │
│ │ │ │
│ │ SYN+ACK, Seq=300, Ack=101 │ │
│ │←───────────────────────────────────────┤ │
│ │ │ │
│ │ ACK, Seq=101, Ack=301 │ │
│ ├───────────────────────────────────────→│ │
│ │ │ │
│ ═══════════ 2단계: 데이터 전송 ═══════════════════════════ │
│ │ │ │
│ │ Seq=101, Len=200 (데이터: GET ...) │ │
│ ├───────────────────────────────────────→│ │
│ │ "101~300번 바이트 보내요" │ │
│ │ │ │
│ │ ACK=301 │ │
│ │←───────────────────────────────────────┤ │
│ │ "301번부터 보내줘" │ │
│ │ │ │
│ │ Seq=301, Len=1000 (HTML 데이터) │ │
│ │←───────────────────────────────────────┤ │
│ │ "301~1300번 바이트 보내요" │ │
│ │ │ │
│ │ ACK=1301 │ │
│ ├───────────────────────────────────────→│ │
│ │ "1301번부터 보내줘" │ │
│ │ │ │
│ ═══════════ 3단계: 연결 종료 (4-Way Handshake) ═══════════ │
│ │ │ │
│ │ FIN, Seq=301, Ack=1301 │ │
│ ├───────────────────────────────────────→│ │
│ │ │ │
│ │ ACK=302 │ │
│ │←───────────────────────────────────────┤ │
│ │ │ │
│ │ FIN, Seq=1301, Ack=302 │ │
│ │←───────────────────────────────────────┤ │
│ │ │ │
│ │ ACK=1302 │ │
│ ├───────────────────────────────────────→│ │
│ │ │ │
│ │
└─────────────────────────────────────────────────────────────┘Seq/Ack 번호 추적 예시
상세 번호 추적:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
초기 상태:
• 클라이언트 ISN: 100
• 서버 ISN: 300
┌─────────────────────────────────────────────────────────────┐
│ 단계 │ 패킷 내용 │ Seq/Ack 계산 │
├─────────┼──────────────────────────┼───────────────────────┤
│ 1 │ C→S: SYN │ Seq=100 │
│ │ │ (SYN은 Seq 1 소비) │
├─────────┼──────────────────────────┼───────────────────────┤
│ 2 │ S→C: SYN+ACK │ Seq=300, Ack=101 │
│ │ │ (Ack=100+1) │
├─────────┼──────────────────────────┼───────────────────────┤
│ 3 │ C→S: ACK │ Seq=101, Ack=301 │
│ │ │ (Ack=300+1) │
├─────────┼──────────────────────────┼───────────────────────┤
│ 4 │ C→S: 데이터 200B │ Seq=101, Len=200 │
│ │ │ 다음 Seq=101+200=301 │
├─────────┼──────────────────────────┼───────────────────────┤
│ 5 │ S→C: ACK │ Ack=301 │
│ │ │ (101+200=301) │
├─────────┼──────────────────────────┼───────────────────────┤
│ 6 │ S→C: 데이터 1000B │ Seq=301, Len=1000 │
│ │ │ 다음 Seq=301+1000=1301│
├─────────┼──────────────────────────┼───────────────────────┤
│ 7 │ C→S: ACK │ Ack=1301 │
│ │ │ (301+1000=1301) │
└─────────┴──────────────────────────┴───────────────────────┘5. 재전송 제어
재전송이 필요한 경우
┌─────────────────────────────────────────────────────────────┐
│ 재전송 제어 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 정의: │
│ • 데이터가 손상되거나 유실된 경우 다시 보내는 것 │
│ • TCP의 신뢰성 보장 핵심 메커니즘 │
│ │
│ │
│ 재전송이 필요한 상황: │
│ ───────────────────────────────────────── │
│ │
│ 1. 패킷 손실 (Packet Loss) │
│ • 네트워크 혼잡으로 라우터가 패킷 버림 │
│ • 물리적 연결 문제 │
│ │
│ 2. 패킷 손상 (Packet Corruption) │
│ • 체크섬 검증 실패 │
│ • 수신측이 패킷 폐기 │
│ │
│ 3. ACK 손실 │
│ • 수신측은 받았지만 ACK가 손실됨 │
│ • 송신측은 ACK 못 받음 → 재전송 │
│ │
└─────────────────────────────────────────────────────────────┘타임아웃 재전송 (RTO)
┌─────────────────────────────────────────────────────────────┐
│ 타임아웃 재전송 (Retransmission Timeout) │
├─────────────────────────────────────────────────────────────┤
│ │
│ 원리: │
│ • 데이터 전송 후 타이머 시작 │
│ • 타임아웃 내에 ACK 없으면 재전송 │
│ │
│ │
│ [송신측] [수신측] │
│ │ │ │
│ │ Seq=1000, Len=100 │ │
│ ├─────────────────────╳ │ 패킷 손실! │
│ │ │ │
│ │ ← 타이머 시작 → │ │
│ │ │ │
│ │ ... 시간 경과 ... │ │
│ │ │ │
│ │ ⏰ 타임아웃! │ │
│ │ │ │
│ │ Seq=1000, Len=100 (재전송) │ │
│ ├────────────────────────────────────→│ ✓ 받음 │
│ │ │ │
│ │ ACK=1100 │ │
│ │←────────────────────────────────────┤ │
│ │ │ │
│ │
│ │
│ RTO (Retransmission Timeout) 계산: │
│ ───────────────────────────────────────── │
│ • RTT (Round Trip Time) 기반으로 동적 계산 │
│ • RTO = SRTT + 4 × RTTVAR │
│ - SRTT: Smoothed RTT (평균 RTT) │
│ - RTTVAR: RTT 변동폭 │
│ • 재전송 실패 시 RTO 2배로 증가 (지수 백오프) │
│ │
└─────────────────────────────────────────────────────────────┘빠른 재전송 (Fast Retransmit)
┌─────────────────────────────────────────────────────────────┐
│ 빠른 재전송 (Fast Retransmit) │
├─────────────────────────────────────────────────────────────┤
│ │
│ 원리: │
│ • 중복 ACK 3개 받으면 타임아웃 기다리지 않고 즉시 재전송 │
│ • 더 빠른 복구 가능 │
│ │
│ │
│ [송신측] [수신측] │
│ │ │ │
│ │ Seq=1000, Len=100 │ │
│ ├────────────────────────────────────→│ ✓ 받음 │
│ │ │ │
│ │ Seq=1100, Len=100 │ │
│ ├─────────────────────╳ │ 손실! │
│ │ │ │
│ │ Seq=1200, Len=100 │ │
│ ├────────────────────────────────────→│ ✓ 받음 │
│ │ │ (순서 아님) │
│ │ ACK=1100 │ ← 중복 ACK 1 │
│ │←────────────────────────────────────┤ │
│ │ │ │
│ │ Seq=1300, Len=100 │ │
│ ├────────────────────────────────────→│ ✓ 받음 │
│ │ ACK=1100 │ ← 중복 ACK 2 │
│ │←────────────────────────────────────┤ │
│ │ │ │
│ │ Seq=1400, Len=100 │ │
│ ├────────────────────────────────────→│ ✓ 받음 │
│ │ ACK=1100 │ ← 중복 ACK 3 │
│ │←────────────────────────────────────┤ │
│ │ │ │
│ │ ┌────────────────────────────┐ │ │
│ │ │ 중복 ACK 3개! 즉시 재전송! │ │ │
│ │ └────────────────────────────┘ │ │
│ │ │ │
│ │ Seq=1100, Len=100 (재전송) │ │
│ ├────────────────────────────────────→│ ✓ 받음 │
│ │ │ │
│ │ ACK=1500 │ │
│ │←────────────────────────────────────┤ │
│ │ "1500번까지 다 받았어!" │ │
│ │ (버퍼에 쌓인 것도 한 번에 확인) │ │
│ │ │ │
│ │
│ │
│ 왜 3개인가? │
│ ───────────────────────────────────────── │
│ • 1~2개: 단순 순서 뒤바뀜일 수 있음 (손실 아님) │
│ • 3개: 높은 확률로 실제 손실 발생 │
│ │
└─────────────────────────────────────────────────────────────┘6. 윈도우 크기 (Window Size)
윈도우 크기란?
┌─────────────────────────────────────────────────────────────┐
│ 윈도우 크기 (Window Size) │
├─────────────────────────────────────────────────────────────┤
│ │
│ 정의: │
│ • 수신측이 한 번에 받을 수 있는 데이터 크기 (바이트) │
│ • TCP 헤더의 16비트 필드 │
│ • 최대 65,535 바이트 (옵션으로 확장 가능) │
│ │
│ │
│ 목적: │
│ ───────────────────────────────────────── │
│ • 흐름 제어 (Flow Control) │
│ • 수신측 버퍼 오버플로우 방지 │
│ • 송수신 속도 조절 │
│ │
│ │
│ 비유: │
│ ───────────────────────────────────────── │
│ │
│ 수신측 = 물탱크, 윈도우 크기 = 탱크 여유 공간 │
│ │
│ ┌─────────────┐ │
│ │ ▓▓▓▓▓▓▓▓ │ ← 이미 받은 데이터 (처리 대기 중) │
│ │ ▓▓▓▓▓▓▓▓ │ │
│ │ │ ← 윈도우 크기 (더 받을 수 있는 공간) │
│ │ │ │
│ └─────────────┘ │
│ │
│ 탱크가 가득 차면 → 윈도우 크기 = 0 → "잠깐 멈춰!" │
│ 탱크가 비면 → 윈도우 크기 증가 → "더 보내도 돼!" │
│ │
└─────────────────────────────────────────────────────────────┘버퍼와 오버플로우
┌─────────────────────────────────────────────────────────────┐
│ 버퍼와 오버플로우 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 버퍼 (Buffer): │
│ • 수신한 세그먼트를 임시 저장하는 메모리 공간 │
│ • 애플리케이션이 데이터를 가져갈 때까지 보관 │
│ │
│ │
│ 오버플로우 (Overflow): │
│ • 데이터가 버퍼 용량을 초과하는 현상 │
│ • 새로운 데이터를 받을 수 없음 → 패킷 폐기 │
│ │
│ │
│ 정상 상태: │
│ ───────────────────────────────────────── │
│ │
│ ┌─────────────────────────────────────┐ │
│ │ 수신 버퍼 (4096 바이트) │ │
│ ├─────────────────────────────────────┤ │
│ │ ▓▓▓▓▓▓▓▓▓▓│ │ │
│ │ 사용 중 │ 여유 공간 │ │
│ │ (1000B) │ (3096B) │ │
│ │ │ = 윈도우 크기 │ │
│ └─────────────────────────────────────┘ │
│ │
│ │
│ 오버플로우 위험: │
│ ───────────────────────────────────────── │
│ │
│ ┌─────────────────────────────────────┐ │
│ │ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓│ ← 거의 가득! │
│ │ 사용 중 (4000B) │ 여유 96B │ │
│ └─────────────────────────────────────┘ │
│ │
│ → 윈도우 크기 = 96 광고 → 송신측은 96바이트만 전송 │
│ │
│ │
│ 오버플로우 발생: │
│ ───────────────────────────────────────── │
│ │
│ ┌─────────────────────────────────────┐ ┌───┐ │
│ │ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓│ │ ✗ │ ← 폐기! │
│ │ 가득 참! (4096B) │ └───┘ │
│ └─────────────────────────────────────┘ 새 패킷 │
│ │
│ → 윈도우 크기 = 0 광고 → 송신측 전송 중단 │
│ │
└─────────────────────────────────────────────────────────────┘윈도우 크기 조절 과정
┌─────────────────────────────────────────────────────────────┐
│ 윈도우 크기 조절 흐름 │
├─────────────────────────────────────────────────────────────┤
│ │
│ [송신측] [수신측] │
│ 버퍼: 4096B │
│ │ │ │
│ │ ── 3-Way Handshake ── │ │
│ │ Window=4096 │ │
│ │←────────────────────────────────────┤ "4096B 가능" │
│ │ │ │
│ │ 1000B 전송 │ │
│ ├────────────────────────────────────→│ 사용: 1000B │
│ │ │ │
│ │ 1000B 전송 │ │
│ ├────────────────────────────────────→│ 사용: 2000B │
│ │ │ │
│ │ ACK, Window=2096 │ │
│ │←────────────────────────────────────┤ "2096B 가능" │
│ │ │ │
│ │ 1000B 전송 │ │
│ ├────────────────────────────────────→│ 사용: 3000B │
│ │ │ │
│ │ 1000B 전송 │ │
│ ├────────────────────────────────────→│ 사용: 4000B │
│ │ │ │
│ │ ACK, Window=96 │ │
│ │←────────────────────────────────────┤ "96B만 가능!" │
│ │ │ │
│ │ 96B만 전송 │ │
│ ├────────────────────────────────────→│ 사용: 4096B │
│ │ │ │
│ │ ACK, Window=0 │ 가득 참! │
│ │←────────────────────────────────────┤ "잠깐 멈춰!" │
│ │ │ │
│ │ ═══════ 전송 중단 ═══════ │ │
│ │ │ │
│ │ (애플리케이션이 데이터 처리) │ 처리 중... │
│ │ │ │
│ │ Window Update, Window=2000 │ │
│ │←────────────────────────────────────┤ "2000B 비었어"│
│ │ │ │
│ │ ═══════ 전송 재개 ═══════ │ │
│ │ │ │
│ │
└─────────────────────────────────────────────────────────────┘슬라이딩 윈도우 (Sliding Window)
┌─────────────────────────────────────────────────────────────┐
│ 슬라이딩 윈도우 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 정의: │
│ • ACK를 받을 때마다 윈도우가 "슬라이딩"하는 방식 │
│ • ACK 기다리지 않고 여러 세그먼트 연속 전송 가능 │
│ • 네트워크 효율성 극대화 │
│ │
│ │
│ 송신측 버퍼 상태: │
│ ───────────────────────────────────────── │
│ │
│ 초기 상태 (윈도우 크기 = 4): │
│ ┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐ │
│ │1 │2 │3 │4 │5 │6 │7 │8 │9 │10│ │
│ └──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘ │
│ ├────────────┤ │
│ └─ 전송 가능 ─┘ │
│ │
│ │
│ 1~2 전송 후: │
│ ┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐ │
│ │● │● │3 │4 │5 │6 │7 │8 │9 │10│ │
│ └──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘ │
│ │전송됨 │← 전송 가능 →│ │
│ ACK대기 │
│ │
│ │
│ ACK(3) 수신 → 윈도우 슬라이딩: │
│ ┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐ │
│ │✓ │✓ │● │● │5 │6 │7 │8 │9 │10│ │
│ └──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘ │
│ ACK됨 │전송됨│← 전송 가능 →│ │
│ ACK대기 │
│ │
│ ↓ 윈도우가 오른쪽으로 슬라이딩! │
│ │
│ │
│ 비효율적 방식 (Stop-and-Wait): │
│ ───────────────────────────────────────── │
│ 송신 → ACK대기 → ACK수신 → 송신 → ACK대기 → ... │
│ • 한 번에 하나씩만 전송 │
│ • 네트워크 유휴 시간 많음 │
│ │
│ │
│ 효율적 방식 (슬라이딩 윈도우): │
│ ───────────────────────────────────────── │
│ 송신1 → 송신2 → 송신3 → 송신4 → ACK(1-2) → 송신5 → ... │
│ • 윈도우 크기만큼 연속 전송 │
│ • 파이프라인 효과 │
│ │
└─────────────────────────────────────────────────────────────┘윈도우 크기 확장 (Window Scaling)
┌─────────────────────────────────────────────────────────────┐
│ 윈도우 스케일링 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 문제: │
│ • TCP 헤더의 윈도우 크기는 16비트 │
│ • 최대 65,535 바이트 (64KB) │
│ • 고속 네트워크에서는 너무 작음! │
│ │
│ │
│ 해결: Window Scale 옵션 (RFC 1323) │
│ ───────────────────────────────────────── │
│ • 3-Way Handshake 시 협상 │
│ • 윈도우 크기에 2^n 을 곱함 │
│ • 최대 스케일 팩터: 14 (2^14 = 16,384배) │
│ │
│ │
│ 실제 윈도우 크기 = 헤더의 윈도우 값 × 2^(스케일 팩터) │
│ │
│ │
│ 예시: │
│ ───────────────────────────────────────── │
│ │
│ 스케일 팩터 = 7 │
│ 헤더의 윈도우 = 8192 │
│ │
│ 실제 윈도우 = 8192 × 2^7 │
│ = 8192 × 128 │
│ = 1,048,576 바이트 (1MB) │
│ │
│ │
│ 최대 윈도우 크기: │
│ 65,535 × 2^14 = 1,073,725,440 바이트 (약 1GB) │
│ │
│ │
│ 협상 과정: │
│ ───────────────────────────────────────── │
│ │
│ [클라이언트] [서버] │
│ │ │ │
│ │ SYN, Window=65535 │ │
│ │ Option: Window Scale=7 │ │
│ ├─────────────────────────────────→│ │
│ │ │ │
│ │ SYN+ACK, Window=65535 │ │
│ │ Option: Window Scale=8 │ │
│ │←─────────────────────────────────┤ │
│ │ │ │
│ │ ACK │ │
│ ├─────────────────────────────────→│ │
│ │ │ │
│ │ (이후 통신에서 스케일 팩터 적용)│ │
│ │ │ │
│ │
└─────────────────────────────────────────────────────────────┘7. 실무 활용
Wireshark로 Seq/Ack 분석
Wireshark에서 Seq/Ack 번호 확인:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
No. Time Source Dest Info
1 0.000 Client Server [SYN] Seq=0
2 0.015 Server Client [SYN, ACK] Seq=0 Ack=1
3 0.015 Client Server [ACK] Seq=1 Ack=1
4 0.016 Client Server [PSH, ACK] Seq=1 Ack=1 Len=200
5 0.025 Server Client [ACK] Seq=1 Ack=201
6 0.030 Server Client [PSH, ACK] Seq=1 Ack=201 Len=1500
7 0.031 Client Server [ACK] Seq=201 Ack=1501
패킷 4번 상세:
┌───────────────────────────────────────────────────────────┐
│ Transmission Control Protocol │
│ ├─ Source Port: 52341 │
│ ├─ Destination Port: 80 │
│ ├─ Sequence Number: 1 (relative) │
│ ├─ Acknowledgment Number: 1 (relative) │
│ ├─ Header Length: 20 bytes │
│ ├─ Flags: 0x018 (PSH, ACK) │
│ ├─ Window: 65535 │
│ ├─ TCP Segment Len: 200 │
│ └─ [Next Seq: 201] ← Wireshark가 계산해줌 │
└───────────────────────────────────────────────────────────┘
유용한 Wireshark 필터:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# 특정 Seq 번호
tcp.seq == 1000
# 특정 ACK 번호
tcp.ack == 2000
# 재전송 패킷
tcp.analysis.retransmission
# 중복 ACK
tcp.analysis.duplicate_ack
# 순서 어긋난 패킷
tcp.analysis.out_of_order
# 윈도우 크기 0
tcp.window_size == 0
# 윈도우 업데이트
tcp.analysis.window_updatenetstat으로 윈도우 크기 확인
Windows:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
> netstat -an
활성 연결
프로토콜 로컬 주소 외부 주소 상태
TCP 192.168.1.10:52341 142.250.185.78:443 ESTABLISHED
상세 정보 (관리자):
> netsh interface tcp show global
TCP 전역 매개 변수
----------------------------------------------
수신측 창 자동 조정 수준 : normal
추가 기능 창 휴리스틱 : disabled
ECN 기능 : disabled
타임스탬프 : disabled
Linux:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
$ ss -ti
State Recv-Q Send-Q Local:Port Peer:Port
ESTAB 0 0 192.168.1.10:52341 142.250.185.78:443
cubic wscale:7,7 rto:204 rtt:15.2/7.6 ato:40 mss:1448
pmtu:1500 rcvmss:1448 advmss:1448 cwnd:10 bytes_sent:1234
bytes_received:5678 segs_out:20 segs_in:15
data_segs_out:10 data_segs_in:8 send 7.6Mbps
lastsnd:1234 lastrcv:1234 lastack:1234 pacing_rate 15.2Mbps
delivery_rate 7.6Mbps app_limited busy:1234ms
rcv_rtt:15 rcv_space:14600 rcv_ssthresh:64088
minrtt:15
주요 지표:
• wscale:7,7 - 윈도우 스케일 팩터 (송신:7, 수신:7)
• cwnd:10 - 혼잡 윈도우 (10 세그먼트)
• rcv_space - 수신 버퍼 크기
• rto:204 - 재전송 타임아웃 (204ms)
• rtt:15.2 - Round Trip Time (15.2ms)성능 튜닝 팁
┌─────────────────────────────────────────────────────────────┐
│ TCP 성능 튜닝 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 버퍼 크기 조정 (Linux) │
│ ───────────────────────────────────────── │
│ │
│ # 현재 설정 확인 │
│ $ sysctl net.core.rmem_max │
│ $ sysctl net.core.wmem_max │
│ $ sysctl net.ipv4.tcp_rmem │
│ $ sysctl net.ipv4.tcp_wmem │
│ │
│ # 수신 버퍼 최대값 증가 (예: 16MB) │
│ $ sysctl -w net.core.rmem_max=16777216 │
│ │
│ # 송신 버퍼 최대값 증가 (예: 16MB) │
│ $ sysctl -w net.core.wmem_max=16777216 │
│ │
│ # TCP 버퍼 자동 조정 (min, default, max) │
│ $ sysctl -w net.ipv4.tcp_rmem="4096 87380 16777216" │
│ $ sysctl -w net.ipv4.tcp_wmem="4096 65536 16777216" │
│ │
│ │
│ 2. 윈도우 스케일링 활성화 │
│ ───────────────────────────────────────── │
│ │
│ $ sysctl -w net.ipv4.tcp_window_scaling=1 │
│ │
│ │
│ 3. 적절한 BDP 계산 │
│ ───────────────────────────────────────── │
│ │
│ BDP (Bandwidth-Delay Product): │
│ = 대역폭 × RTT │
│ │
│ 예: 1Gbps 링크, RTT=100ms │
│ BDP = 1,000,000,000 bps × 0.1s │
│ = 100,000,000 bits │
│ = 12,500,000 bytes (약 12MB) │
│ │
│ → 버퍼 크기를 BDP 이상으로 설정해야 최대 성능 │
│ │
│ │
│ 4. Windows에서 조정 │
│ ───────────────────────────────────────── │
│ │
│ # 자동 튜닝 활성화 │
│ > netsh interface tcp set global autotuninglevel=normal │
│ │
│ # 옵션: disabled, highlyrestricted, restricted, │
│ # normal, experimental │
│ │
└─────────────────────────────────────────────────────────────┘핵심 정리
| 개념 | 설명 |
|---|---|
| 일련번호 (Seq) | 전송하는 데이터의 바이트 순서 번호 |
| 확인 응답 번호 (Ack) | 다음에 받기 원하는 바이트 번호 |
| ISN | 연결 시작 시 사용하는 초기 일련번호 (랜덤) |
| 누적 ACK | ACK=N은 “N-1까지 모두 받음"을 의미 |
| 재전송 제어 | 손실/손상된 데이터를 다시 보내는 메커니즘 |
| RTO | 재전송 타임아웃 (RTT 기반 계산) |
| 빠른 재전송 | 중복 ACK 3개 시 즉시 재전송 |
| 버퍼 | 수신 데이터를 임시 저장하는 공간 |
| 오버플로우 | 버퍼 용량 초과 현상 |
| 윈도우 크기 | 수신 가능한 데이터 크기 (흐름 제어용) |
| 슬라이딩 윈도우 | ACK 기다리지 않고 연속 전송하는 기법 |
전송 과정 요약
┌─────────────────────────────────────────────────────────────┐
│ 데이터 전송 핵심 개념 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 일련번호 (Sequence Number) │
│ ───────────────────────────────────────── │
│ 송신측: "이건 1000번 바이트부터 시작해요" │
│ │
│ 2. 확인 응답 번호 (ACK Number) │
│ ───────────────────────────────────────── │
│ 수신측: "1500번부터 보내줘" (1499까지 받았어) │
│ │
│ 3. 재전송 │
│ ───────────────────────────────────────── │
│ • 타임아웃: 일정 시간 내 ACK 없으면 재전송 │
│ • 빠른 재전송: 중복 ACK 3개면 즉시 재전송 │
│ │
│ 4. 흐름 제어 (윈도우) │
│ ───────────────────────────────────────── │
│ 수신측: "4096바이트만 받을 수 있어" → Window=4096 │
│ 수신측: "버퍼 가득!" → Window=0 → 전송 중단 │
│ 수신측: "다시 비었어" → Window=2000 → 전송 재개 │
│ │
│ │
│ 데이터 전송 흐름: │
│ ───────────────────────────────────────── │
│ │
│ [송신측] [수신측] │
│ │ │ │
│ │ Seq=1000, Len=500 │ │
│ ├─────────────────────────────────→│ │
│ │ "바이트 1000~1499" │ │
│ │ │ │
│ │ ACK=1500, Win=3000 │ │
│ │←─────────────────────────────────┤ │
│ │ "1500번 보내줘, 3000B 가능" │ │
│ │ │ │
│ │ Seq=1500, Len=1000 │ │
│ ├─────────────────────────────────→│ │
│ │ "바이트 1500~2499" │ │
│ │ │ │
│ │
└─────────────────────────────────────────────────────────────┘용어 정리
- 일련번호 (Sequence Number): 전송하는 데이터의 바이트 순서를 나타내는 32비트 번호
- 확인 응답 번호 (Acknowledgment Number): 다음에 받기 원하는 바이트 번호
- ISN (Initial Sequence Number): 연결 시작 시 사용하는 초기 일련번호 (보안상 랜덤)
- 재전송 제어 (Retransmission Control): 데이터 손실/손상 시 다시 전송하는 메커니즘
- RTO (Retransmission Timeout): 재전송을 결정하는 타임아웃 시간
- RTT (Round Trip Time): 패킷이 왕복하는 데 걸리는 시간
- 빠른 재전송 (Fast Retransmit): 중복 ACK 3개 수신 시 즉시 재전송
- 버퍼 (Buffer): 수신한 데이터를 임시 저장하는 메모리 공간
- 오버플로우 (Overflow): 데이터가 버퍼 용량을 초과하는 현상
- 윈도우 크기 (Window Size): 수신측이 한 번에 받을 수 있는 데이터 크기
- 슬라이딩 윈도우 (Sliding Window): ACK를 기다리지 않고 여러 세그먼트를 연속 전송하는 기법
- 윈도우 스케일링 (Window Scaling): 윈도우 크기를 64KB 이상으로 확장하는 TCP 옵션
- BDP (Bandwidth-Delay Product): 대역폭 × 지연시간, 최적 버퍼 크기 계산에 사용