TCP의 구조

TCP의 구조

1. TCP란?

TCP 개념

┌─────────────────────────────────────────────────────────────┐
│                  TCP (Transmission Control Protocol)        │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  정의:                                                      │
│  • 전송 계층에서 동작하는 연결 지향형 프로토콜               │
│  • 신뢰성 있는 데이터 전송을 보장                           │
│  • 순서 보장, 오류 검출, 재전송 기능 제공                   │
│                                                             │
│  핵심 특징:                                                 │
│  ─────────────────────────────────────────                  │
│  • 연결 지향 (Connection-Oriented)                          │
│  • 양방향 통신 (Full-Duplex)                                │
│  • 바이트 스트림 (Byte Stream) 전송                         │
│  • 흐름 제어 (Flow Control)                                 │
│  • 혼잡 제어 (Congestion Control)                           │
│                                                             │
└─────────────────────────────────────────────────────────────┘

TCP 세그먼트

TCP 헤더가 붙은 데이터를 세그먼트(Segment)라고 한다:

┌─────────────────────────────────────────────────────────────┐
│                                                             │
│  [애플리케이션 계층]                                         │
│         │                                                   │
│         ↓ 데이터                                            │
│  ┌─────────────────────────────────────────────┐            │
│  │                 데이터                       │            │
│  └─────────────────────────────────────────────┘            │
│         │                                                   │
│         ↓ TCP 헤더 추가 (전송 계층)                          │
│  ┌───────────┬─────────────────────────────────┐            │
│  │ TCP 헤더  │            데이터                │            │
│  │(20~60 bytes)│                               │            │
│  └───────────┴─────────────────────────────────┘            │
│         ↑                                                   │
│         └──────── TCP 세그먼트 ─────────────────            │
│                                                             │
│         ↓ IP 헤더 추가 (네트워크 계층)                       │
│  ┌─────────┬───────────┬───────────────────────┐            │
│  │ IP 헤더 │ TCP 헤더  │        데이터          │            │
│  └─────────┴───────────┴───────────────────────┘            │
│         ↑                                                   │
│         └──────── IP 패킷 ──────────────────────            │
│                                                             │
└─────────────────────────────────────────────────────────────┘

2. TCP 헤더 구조

TCP 헤더 상세

┌─────────────────────────────────────────────────────────────┐
│                   TCP 헤더 구조 (20~60 바이트)               │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  비트:  0                16                 31              │
│        ├─────────────────┼─────────────────┤               │
│     0  │  출발지 포트     │  목적지 포트     │               │
│        │   (16비트)       │   (16비트)      │               │
│        ├─────────────────┴─────────────────┤               │
│    32  │          순서 번호 (Sequence Number)│               │
│        │                (32비트)            │               │
│        ├───────────────────────────────────┤               │
│    64  │       확인 응답 번호 (ACK Number)  │               │
│        │                (32비트)            │               │
│        ├────┬──────┬────┬──────────────────┤               │
│    96  │헤더│예약  │제어│   윈도우 크기     │               │
│        │길이│(6bit)│비트│    (16비트)      │               │
│        │(4) │      │(6) │                  │               │
│        ├────┴──────┴────┼──────────────────┤               │
│   128  │  체크섬 (16비트)│ 긴급 포인터(16비트)│               │
│        ├────────────────┴──────────────────┤               │
│   160  │         옵션 (0~40 바이트)         │               │
│        ├───────────────────────────────────┤               │
│        │              데이터                │               │
│        │               ...                 │               │
│        └───────────────────────────────────┘               │
│                                                             │
└─────────────────────────────────────────────────────────────┘

각 필드 상세 설명

┌─────────────────────────────────────────────────────────────┐
│                    TCP 헤더 필드 설명                        │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. 출발지 포트 번호 (Source Port) - 16비트                  │
│  ─────────────────────────────────────────                  │
│     • 송신 애플리케이션의 포트 번호                          │
│     • 범위: 0 ~ 65535                                       │
│     • 예: 52341 (클라이언트의 임시 포트)                     │
│                                                             │
│  2. 목적지 포트 번호 (Destination Port) - 16비트             │
│  ─────────────────────────────────────────                  │
│     • 수신 애플리케이션의 포트 번호                          │
│     • 예: 80 (HTTP), 443 (HTTPS), 22 (SSH)                  │
│                                                             │
│  3. 순서 번호 (Sequence Number) - 32비트                     │
│  ─────────────────────────────────────────                  │
│     • 전송하는 데이터의 첫 번째 바이트 번호                  │
│     • 초기값: 랜덤 (ISN: Initial Sequence Number)           │
│     • 순서 보장 및 재조립에 사용                             │
│                                                             │
│  4. 확인 응답 번호 (ACK Number) - 32비트                     │
│  ─────────────────────────────────────────                  │
│     • 다음에 받기 기대하는 바이트 번호                       │
│     • "여기까지 잘 받았으니, 다음 번호 보내줘"               │
│     • ACK 플래그가 1일 때만 유효                             │
│                                                             │
│  5. 헤더 길이 (Data Offset) - 4비트                          │
│  ─────────────────────────────────────────                  │
│     • TCP 헤더의 길이를 4바이트 단위로 표시                  │
│     • 최소 5 (20바이트), 최대 15 (60바이트)                  │
│     • 옵션 포함 여부에 따라 달라짐                           │
│                                                             │
│  6. 예약 (Reserved) - 6비트                                  │
│  ─────────────────────────────────────────                  │
│     • 미래를 위해 예약된 필드                                │
│     • 항상 0으로 설정                                        │
│                                                             │
│  7. 제어 비트 (Control Flags) - 6비트                        │
│  ─────────────────────────────────────────                  │
│     • 연결 제어 정보를 담는 플래그                           │
│     • URG, ACK, PSH, RST, SYN, FIN                          │
│     (아래에서 상세 설명)                                     │
│                                                             │
│  8. 윈도우 크기 (Window Size) - 16비트                       │
│  ─────────────────────────────────────────                  │
│     • 수신 가능한 데이터 크기 (바이트)                       │
│     • 흐름 제어에 사용                                       │
│     • 최대 65535 바이트 (옵션으로 확장 가능)                 │
│                                                             │
│  9. 체크섬 (Checksum) - 16비트                               │
│  ─────────────────────────────────────────                  │
│     • 헤더와 데이터의 오류 검출용                            │
│     • 의사 헤더(Pseudo Header) 포함하여 계산                 │
│                                                             │
│ 10. 긴급 포인터 (Urgent Pointer) - 16비트                    │
│  ─────────────────────────────────────────                  │
│     • URG 플래그가 1일 때 유효                               │
│     • 긴급 데이터의 마지막 위치                              │
│                                                             │
│ 11. 옵션 (Options) - 가변 (0~40 바이트)                      │
│  ─────────────────────────────────────────                  │
│     • MSS, 윈도우 스케일, 타임스탬프 등                      │
│     • 4바이트 단위로 패딩                                    │
│                                                             │
└─────────────────────────────────────────────────────────────┘

3. 제어 비트 (Control Flags)

6개의 제어 비트

┌─────────────────────────────────────────────────────────────┐
│                      제어 비트 (6비트)                       │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│     비트 위치:                                              │
│     ┌─────┬─────┬─────┬─────┬─────┬─────┐                  │
│     │ URG │ ACK │ PSH │ RST │ SYN │ FIN │                  │
│     └─────┴─────┴─────┴─────┴─────┴─────┘                  │
│       5     4     3     2     1     0                       │
│                                                             │
│  초깃값: 모두 0                                             │
│  활성화: 해당 비트가 1이 됨                                  │
│                                                             │
└─────────────────────────────────────────────────────────────┘

각 플래그의 역할

┌─────────────────────────────────────────────────────────────┐
│                    제어 비트 상세 설명                       │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  URG (Urgent) - 긴급 비트                                   │
│  ─────────────────────────────────────────                  │
│  • 긴급 데이터 포함 표시                                    │
│  • 긴급 포인터 필드와 함께 사용                             │
│  • 수신측은 다른 데이터보다 먼저 처리                       │
│  • 예: Ctrl+C로 원격 프로그램 종료                          │
│                                                             │
│  ACK (Acknowledgment) - 확인 응답 비트                      │
│  ─────────────────────────────────────────                  │
│  • 확인 응답 번호 필드가 유효함을 표시                      │
│  • 연결 설정 후 거의 항상 1로 설정                          │
│  • "이전 데이터 잘 받았어"                                  │
│                                                             │
│  PSH (Push) - 푸시 비트                                     │
│  ─────────────────────────────────────────                  │
│  • 수신측에 즉시 전달 요청                                  │
│  • 버퍼에 쌓지 말고 바로 애플리케이션에 전달                │
│  • 대화형 통신에서 사용 (SSH, Telnet)                       │
│                                                             │
│  RST (Reset) - 리셋 비트                                    │
│  ─────────────────────────────────────────                  │
│  • 연결 강제 종료                                           │
│  • 비정상적인 상황에서 연결 초기화                          │
│  • 예: 존재하지 않는 포트에 연결 시도                       │
│                                                             │
│  SYN (Synchronize) - 동기화 비트                            │
│  ─────────────────────────────────────────                  │
│  • 연결 설정 요청                                           │
│  • 순서 번호 동기화                                         │
│  • 3-Way Handshake의 첫 번째와 두 번째 단계에서 사용       │
│                                                             │
│  FIN (Finish) - 종료 비트                                   │
│  ─────────────────────────────────────────                  │
│  • 연결 종료 요청                                           │
│  • "더 이상 보낼 데이터 없어"                               │
│  • 4-Way Handshake에서 사용                                 │
│                                                             │
└─────────────────────────────────────────────────────────────┘

플래그 조합 예시

주요 플래그 조합:

┌──────────┬─────┬─────┬─────┬─────┬─────┬─────┬──────────────┐
│   상황   │ URG │ ACK │ PSH │ RST │ SYN │ FIN │    설명      │
├──────────┼─────┼─────┼─────┼─────┼─────┼─────┼──────────────┤
│ 연결요청 │  0  │  0  │  0  │  0  │  1  │  0  │ SYN          │
├──────────┼─────┼─────┼─────┼─────┼─────┼─────┼──────────────┤
│ 연결응답 │  0  │  1  │  0  │  0  │  1  │  0  │ SYN+ACK      │
├──────────┼─────┼─────┼─────┼─────┼─────┼─────┼──────────────┤
│ 연결확인 │  0  │  1  │  0  │  0  │  0  │  0  │ ACK          │
├──────────┼─────┼─────┼─────┼─────┼─────┼─────┼──────────────┤
│데이터전송│  0  │  1  │  1  │  0  │  0  │  0  │ ACK+PSH      │
├──────────┼─────┼─────┼─────┼─────┼─────┼─────┼──────────────┤
│ 종료요청 │  0  │  1  │  0  │  0  │  0  │  1  │ FIN+ACK      │
├──────────┼─────┼─────┼─────┼─────┼─────┼─────┼──────────────┤
│ 연결리셋 │  0  │  0  │  0  │  1  │  0  │  0  │ RST          │
└──────────┴─────┴─────┴─────┴─────┴─────┴─────┴──────────────┘

4. 3-Way Handshake (연결 설정)

연결 설정 과정

┌─────────────────────────────────────────────────────────────┐
│              3-Way Handshake (TCP 연결 설정)                 │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  [클라이언트]                               [서버]          │
│    (CLOSED)                                (LISTEN)         │
│        │                                       │            │
│        │     Step 1: SYN                       │            │
│        │  ──────────────────────────────────→  │            │
│        │     SYN=1, Seq=1000                   │            │
│        │     "연결하고 싶어요!"                 │            │
│        │                                       │            │
│   (SYN_SENT)                            (SYN_RECEIVED)      │
│        │                                       │            │
│        │     Step 2: SYN + ACK                 │            │
│        │  ←──────────────────────────────────  │            │
│        │     SYN=1, ACK=1                      │            │
│        │     Seq=2000, Ack=1001                │            │
│        │     "좋아요! 나도 연결해요!"           │            │
│        │                                       │            │
│        │     Step 3: ACK                       │            │
│        │  ──────────────────────────────────→  │            │
│        │     ACK=1                             │            │
│        │     Seq=1001, Ack=2001                │            │
│        │     "확인! 시작해요!"                  │            │
│        │                                       │            │
│  (ESTABLISHED)                          (ESTABLISHED)       │
│        │                                       │            │
│        │   ═══════ 데이터 전송 가능 ═══════   │            │
│                                                             │
└─────────────────────────────────────────────────────────────┘

단계별 상세 설명

Step 1: SYN (연결 요청)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

클라이언트 → 서버:

┌───────────────────────────────────────────────────────────┐
│  TCP 헤더 내용:                                           │
│  • SYN = 1 (연결 요청)                                    │
│  • Sequence Number = 1000 (초기 순서 번호, ISN)           │
│  • ACK = 0                                                │
│  • Acknowledgment Number = 0 (아직 사용 안 함)            │
│                                                           │
│  의미:                                                    │
│  "안녕하세요! 연결하고 싶어요.                            │
│   내 순서 번호는 1000부터 시작할게요."                    │
└───────────────────────────────────────────────────────────┘


Step 2: SYN + ACK (연결 수락)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

서버 → 클라이언트:

┌───────────────────────────────────────────────────────────┐
│  TCP 헤더 내용:                                           │
│  • SYN = 1 (서버도 연결 요청)                             │
│  • ACK = 1 (클라이언트 SYN 확인)                          │
│  • Sequence Number = 2000 (서버의 ISN)                    │
│  • Acknowledgment Number = 1001 (다음에 받을 번호)        │
│                                                           │
│  의미:                                                    │
│  "네! 연결 수락해요.                                      │
│   당신 SYN 잘 받았어요 (1000번). 다음은 1001번 보내세요.  │
│   내 순서 번호는 2000부터 시작할게요."                    │
└───────────────────────────────────────────────────────────┘


Step 3: ACK (연결 확인)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

클라이언트 → 서버:

┌───────────────────────────────────────────────────────────┐
│  TCP 헤더 내용:                                           │
│  • SYN = 0                                                │
│  • ACK = 1 (서버 SYN 확인)                                │
│  • Sequence Number = 1001                                 │
│  • Acknowledgment Number = 2001 (다음에 받을 번호)        │
│                                                           │
│  의미:                                                    │
│  "알았어요! 서버 SYN 잘 받았어요 (2000번).                │
│   다음은 2001번 보내세요. 이제 시작해요!"                 │
└───────────────────────────────────────────────────────────┘

→ 연결 완료! 양쪽 모두 ESTABLISHED 상태

왜 3-Way인가?

┌─────────────────────────────────────────────────────────────┐
│              3-Way Handshake가 필요한 이유                  │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. 양방향 통신 확인                                        │
│  ─────────────────────────────────────────                  │
│     • 클라이언트 → 서버: SYN으로 확인                      │
│     • 서버 → 클라이언트: SYN+ACK로 확인                    │
│     • 클라이언트 → 서버: ACK로 최종 확인                   │
│                                                             │
│  2. 순서 번호 동기화                                        │
│  ─────────────────────────────────────────                  │
│     • 양쪽이 서로의 ISN을 교환                              │
│     • 이후 데이터 순서 보장 가능                            │
│                                                             │
│  3. 구형 패킷 방지                                          │
│  ─────────────────────────────────────────                  │
│     • 네트워크에 떠돌던 오래된 SYN 패킷 거부               │
│     • ACK 번호로 현재 연결 구분                             │
│                                                             │
│                                                             │
│  2-Way면 안 되는 이유:                                      │
│  ─────────────────────────────────────────                  │
│                                                             │
│  [클라이언트]                      [서버]                   │
│       │                               │                     │
│       │── SYN ──────────────────────→│                      │
│       │                               │ 연결 수립?          │
│       │←─────────────────── SYN+ACK ─│                      │
│       │                               │                     │
│       │  서버는 클라이언트가 SYN+ACK를                      │
│       │  받았는지 확인할 수 없음!                           │
│       │                               │                     │
│       ╳ 클라이언트가 이미 사라졌을 수도 있음               │
│                                                             │
└─────────────────────────────────────────────────────────────┘

5. 4-Way Handshake (연결 종료)

연결 종료 과정

┌─────────────────────────────────────────────────────────────┐
│              4-Way Handshake (TCP 연결 종료)                 │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  [클라이언트]                               [서버]          │
│  (ESTABLISHED)                           (ESTABLISHED)      │
│        │                                       │            │
│        │     Step 1: FIN                       │            │
│        │  ──────────────────────────────────→  │            │
│        │     FIN=1, ACK=1                      │            │
│        │     Seq=5000, Ack=3000                │            │
│        │     "나는 보낼 데이터 끝!"             │            │
│        │                                       │            │
│   (FIN_WAIT_1)                           (CLOSE_WAIT)       │
│        │                                       │            │
│        │     Step 2: ACK                       │            │
│        │  ←──────────────────────────────────  │            │
│        │     ACK=1                             │            │
│        │     Seq=3000, Ack=5001                │            │
│        │     "알겠어, 잠깐만 기다려"            │            │
│        │                                       │            │
│   (FIN_WAIT_2)                                 │            │
│        │                                       │            │
│        │      (서버가 남은 데이터 전송)         │            │
│        │                                       │            │
│        │     Step 3: FIN                  (LAST_ACK)        │
│        │  ←──────────────────────────────────  │            │
│        │     FIN=1, ACK=1                      │            │
│        │     Seq=3500, Ack=5001                │            │
│        │     "나도 보낼 데이터 끝!"             │            │
│        │                                       │            │
│   (TIME_WAIT)                                  │            │
│        │                                       │            │
│        │     Step 4: ACK                       │            │
│        │  ──────────────────────────────────→  │            │
│        │     ACK=1                             │            │
│        │     Seq=5001, Ack=3501                │            │
│        │     "알겠어, 안녕!"                    │            │
│        │                                       │            │
│        │    (2MSL 대기: 약 60~240초)      (CLOSED)          │
│        │                                       │            │
│    (CLOSED)                                    │            │
│                                                             │
└─────────────────────────────────────────────────────────────┘

왜 4-Way인가?

┌─────────────────────────────────────────────────────────────┐
│              4-Way Handshake가 필요한 이유                  │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  연결은 양방향이므로 각 방향을 따로 닫아야 함               │
│                                                             │
│  3-Way Handshake:                                           │
│  • SYN과 ACK를 한 패킷에 담을 수 있음 (SYN+ACK)            │
│  • 동시에 양방향 연결 시작                                  │
│                                                             │
│  4-Way Handshake:                                           │
│  • FIN과 ACK를 따로 보내야 할 수 있음                       │
│  • 한쪽이 종료해도 상대방은 보낼 데이터가 남아있을 수 있음 │
│                                                             │
│                                                             │
│  예시: 파일 다운로드                                        │
│  ─────────────────────────────────────────                  │
│                                                             │
│  [클라이언트]                    [서버]                     │
│       │                            │                        │
│       │── GET /file.zip ─────────→│                         │
│       │                            │                        │
│       │←────── 파일 데이터 ────────│                         │
│       │         (전송 중...)       │                        │
│       │                            │                        │
│       │── FIN ───────────────────→│  ← 클라이언트: "끝!"   │
│       │                            │                        │
│       │←─────── ACK ───────────────│  ← 서버: "알았어"      │
│       │                            │                        │
│       │←────── 남은 데이터 ─────────│  ← 아직 보낼 게 있음! │
│       │                            │                        │
│       │←─────── FIN ───────────────│  ← 서버: "이제 끝!"   │
│       │                            │                        │
│       │── ACK ───────────────────→│  ← 클라이언트: "확인!" │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Half-Close (반종료)

┌─────────────────────────────────────────────────────────────┐
│                     Half-Close 상태                         │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  클라이언트가 FIN을 보내고 서버가 ACK만 보낸 상태          │
│                                                             │
│  ┌─────────────┐          ┌─────────────┐                  │
│  │  클라이언트 │          │    서버     │                  │
│  │ (FIN_WAIT_2)│          │(CLOSE_WAIT) │                  │
│  ├─────────────┤          ├─────────────┤                  │
│  │             │          │             │                  │
│  │  전송: X    │          │  전송: O    │                  │
│  │  수신: O    │ ←─────── │  수신: X    │                  │
│  │             │  데이터  │             │                  │
│  │             │          │             │                  │
│  └─────────────┘          └─────────────┘                  │
│                                                             │
│  • 클라이언트: 더 이상 데이터를 보내지 않음 (전송 종료)    │
│  • 서버: 아직 데이터를 보낼 수 있음 (수신 가능)            │
│  • 서버가 모든 데이터를 보낸 후 FIN 전송                   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

6. TCP 상태 다이어그램

전체 상태 전이도

┌─────────────────────────────────────────────────────────────┐
│                    TCP 상태 전이도                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│                      ┌───────────┐                          │
│                      │  CLOSED   │                          │
│                      └─────┬─────┘                          │
│                            │                                │
│           ┌────────────────┴────────────────┐               │
│           │                                 │               │
│           ↓ (passive open)                  ↓ (active open) │
│      ┌─────────┐                      ┌───────────┐         │
│      │ LISTEN  │                      │ SYN_SENT  │         │
│      └────┬────┘                      └─────┬─────┘         │
│           │                                 │               │
│           │ (recv SYN,                      │ (recv SYN+ACK,│
│           │  send SYN+ACK)                  │  send ACK)    │
│           ↓                                 │               │
│      ┌──────────────┐                       │               │
│      │ SYN_RECEIVED │                       │               │
│      └──────┬───────┘                       │               │
│             │                               │               │
│             │ (recv ACK)                    │               │
│             ↓                               ↓               │
│      ┌─────────────────────────────────────────┐            │
│      │              ESTABLISHED                │            │
│      └──────────────────┬──────────────────────┘            │
│                         │                                   │
│           ┌─────────────┴─────────────┐                     │
│           │ (send FIN)                │ (recv FIN,          │
│           ↓                           │  send ACK)          │
│      ┌───────────┐                    ↓                     │
│      │ FIN_WAIT_1│              ┌───────────┐               │
│      └─────┬─────┘              │CLOSE_WAIT │               │
│            │                    └─────┬─────┘               │
│            │ (recv ACK)               │ (send FIN)          │
│            ↓                          ↓                     │
│      ┌───────────┐              ┌───────────┐               │
│      │ FIN_WAIT_2│              │ LAST_ACK  │               │
│      └─────┬─────┘              └─────┬─────┘               │
│            │ (recv FIN,               │ (recv ACK)          │
│            │  send ACK)               │                     │
│            ↓                          ↓                     │
│      ┌───────────┐              ┌───────────┐               │
│      │ TIME_WAIT │              │  CLOSED   │               │
│      └─────┬─────┘              └───────────┘               │
│            │ (2MSL timeout)                                 │
│            ↓                                                │
│      ┌───────────┐                                          │
│      │  CLOSED   │                                          │
│      └───────────┘                                          │
│                                                             │
└─────────────────────────────────────────────────────────────┘

주요 상태 설명

┌─────────────────────────────────────────────────────────────┐
│                    TCP 상태 상세 설명                        │
├──────────────┬──────────────────────────────────────────────┤
│     상태     │                   설명                       │
├──────────────┼──────────────────────────────────────────────┤
│    CLOSED    │ 연결 없음 (초기 상태)                        │
├──────────────┼──────────────────────────────────────────────┤
│    LISTEN    │ 서버가 연결 요청 대기 중                     │
├──────────────┼──────────────────────────────────────────────┤
│   SYN_SENT   │ 클라이언트가 SYN 보내고 SYN+ACK 대기        │
├──────────────┼──────────────────────────────────────────────┤
│ SYN_RECEIVED │ 서버가 SYN 받고 SYN+ACK 보낸 후 ACK 대기    │
├──────────────┼──────────────────────────────────────────────┤
│ ESTABLISHED  │ 연결 완료, 데이터 전송 가능                  │
├──────────────┼──────────────────────────────────────────────┤
│  FIN_WAIT_1  │ FIN 보내고 ACK 대기                          │
├──────────────┼──────────────────────────────────────────────┤
│  FIN_WAIT_2  │ FIN에 대한 ACK 받고, 상대방 FIN 대기        │
├──────────────┼──────────────────────────────────────────────┤
│  CLOSE_WAIT  │ FIN 받고 ACK 보냄, 애플리케이션 종료 대기   │
├──────────────┼──────────────────────────────────────────────┤
│   LAST_ACK   │ FIN 보내고 마지막 ACK 대기                   │
├──────────────┼──────────────────────────────────────────────┤
│  TIME_WAIT   │ 마지막 ACK 보낸 후 2MSL 동안 대기           │
├──────────────┼──────────────────────────────────────────────┤
│   CLOSING    │ 동시 종료 시 발생 (드물게 발생)              │
└──────────────┴──────────────────────────────────────────────┘

TIME_WAIT 상태의 중요성

┌─────────────────────────────────────────────────────────────┐
│                   TIME_WAIT 상태                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  정의:                                                      │
│  • 마지막 ACK를 보낸 후 일정 시간 대기하는 상태             │
│  • 대기 시간: 2 × MSL (Maximum Segment Lifetime)           │
│  • MSL: 패킷이 네트워크에서 생존할 수 있는 최대 시간       │
│  • 일반적으로 60초 ~ 240초                                  │
│                                                             │
│                                                             │
│  필요한 이유:                                               │
│  ─────────────────────────────────────────                  │
│                                                             │
│  1. 지연된 패킷 처리                                        │
│     • 네트워크에 떠돌던 이전 연결의 패킷이                  │
│       새 연결에 영향 주는 것 방지                           │
│                                                             │
│  2. 마지막 ACK 재전송                                       │
│     • 상대방이 ACK를 못 받고 FIN을 재전송할 경우           │
│       다시 ACK를 보낼 수 있음                               │
│                                                             │
│                                                             │
│  예시:                                                      │
│  ─────────────────────────────────────────                  │
│                                                             │
│  [클라이언트]                      [서버]                   │
│       │                               │                     │
│       │←─────── FIN ─────────────────│                      │
│       │                               │                     │
│       │── ACK ───────────────────────→│                      │
│       │                      (ACK 손실!)                    │
│       │                               │                     │
│  (TIME_WAIT)                          │                     │
│       │                               │                     │
│       │←─────── FIN (재전송) ─────────│                      │
│       │                               │                     │
│       │── ACK (재전송) ──────────────→│                      │
│       │                               │                     │
│   2MSL 후                        (CLOSED)                   │
│   (CLOSED)                                                  │
│                                                             │
│                                                             │
│  서버 포트 재사용 문제:                                     │
│  ─────────────────────────────────────────                  │
│  • TIME_WAIT 동안 해당 포트 재사용 불가                     │
│  • 서버 재시작 시 "Address already in use" 오류 발생       │
│  • 해결: SO_REUSEADDR 소켓 옵션 사용                        │
│                                                             │
└─────────────────────────────────────────────────────────────┘

7. 순서 번호와 확인 응답

Sequence Number와 ACK Number 동작

┌─────────────────────────────────────────────────────────────┐
│              순서 번호와 확인 응답 번호                      │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  [클라이언트]                              [서버]           │
│                                                             │
│  ───── 3-Way Handshake 완료 ─────                          │
│  클라이언트 Seq: 1000 시작                                  │
│  서버 Seq: 2000 시작                                        │
│                                                             │
│        │                                    │               │
│        │    데이터 100바이트                │               │
│        │    Seq=1001, Len=100               │               │
│        ├───────────────────────────────────→│               │
│        │    "1001~1100번 바이트 보내요"     │               │
│        │                                    │               │
│        │                                    │               │
│        │           ACK=1101                 │               │
│        │←───────────────────────────────────┤               │
│        │    "1101번부터 보내주세요"          │               │
│        │                                    │               │
│        │                                    │               │
│        │    데이터 200바이트                │               │
│        │    Seq=1101, Len=200               │               │
│        ├───────────────────────────────────→│               │
│        │    "1101~1300번 바이트 보내요"     │               │
│        │                                    │               │
│        │                                    │               │
│        │           ACK=1301                 │               │
│        │←───────────────────────────────────┤               │
│        │    "1301번부터 보내주세요"          │               │
│        │                                    │               │
│                                                             │
└─────────────────────────────────────────────────────────────┘


계산 공식:

┌─────────────────────────────────────────────────────────────┐
│                                                             │
│  다음 Sequence Number = 현재 Seq + 데이터 길이             │
│                                                             │
│  ACK Number = 받은 Seq + 받은 데이터 길이                   │
│             = 다음에 기대하는 Sequence Number               │
│                                                             │
│                                                             │
│  예시:                                                      │
│  • Seq=1001, 데이터=100바이트 전송                          │
│  • 수신측 ACK = 1001 + 100 = 1101                           │
│  • 의미: "1101번부터 보내줘!"                               │
│                                                             │
└─────────────────────────────────────────────────────────────┘

패킷 손실과 재전송

┌─────────────────────────────────────────────────────────────┐
│                   패킷 손실과 재전송                         │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  [송신측]                                  [수신측]         │
│      │                                        │             │
│      │    Seq=1001, Len=100                   │             │
│      ├───────────────────────────────────────→│             │
│      │                                        │ ACK=1101    │
│      │←───────────────────────────────────────│             │
│      │                                        │             │
│      │    Seq=1101, Len=100                   │             │
│      ├──────────────────╳                     │  손실!      │
│      │                                        │             │
│      │    Seq=1201, Len=100                   │             │
│      ├───────────────────────────────────────→│             │
│      │                                        │             │
│      │            ACK=1101 (중복!)            │             │
│      │←───────────────────────────────────────│             │
│      │    "1101번 아직 안 받았어!"            │             │
│      │                                        │             │
│      │    Seq=1301, Len=100                   │             │
│      ├───────────────────────────────────────→│             │
│      │                                        │             │
│      │            ACK=1101 (중복!)            │             │
│      │←───────────────────────────────────────│             │
│      │                                        │             │
│      │    Seq=1401, Len=100                   │             │
│      ├───────────────────────────────────────→│             │
│      │                                        │             │
│      │            ACK=1101 (중복!)            │             │
│      │←───────────────────────────────────────│             │
│      │                                        │             │
│      │  ┌────────────────────────────────┐    │             │
│      │  │ 중복 ACK 3개 → 빠른 재전송!    │    │             │
│      │  └────────────────────────────────┘    │             │
│      │                                        │             │
│      │    Seq=1101, Len=100 (재전송)          │             │
│      ├───────────────────────────────────────→│             │
│      │                                        │             │
│      │            ACK=1501                    │             │
│      │←───────────────────────────────────────│             │
│      │    "1501번부터 보내줘!"                │             │
│      │    (버퍼에 쌓인 패킷도 모두 확인됨)    │             │
│                                                             │
└─────────────────────────────────────────────────────────────┘


재전송 방식:

┌─────────────────────────────────────────────────────────────┐
│                                                             │
│  1. 타임아웃 재전송 (Retransmission Timeout, RTO)           │
│  ─────────────────────────────────────────                  │
│     • ACK를 일정 시간 내에 못 받으면 재전송                 │
│     • RTT(Round Trip Time) 기반으로 RTO 계산               │
│     • 느린 방식이지만 확실함                                │
│                                                             │
│  2. 빠른 재전송 (Fast Retransmit)                           │
│  ─────────────────────────────────────────                  │
│     • 중복 ACK 3개 받으면 즉시 재전송                       │
│     • 타임아웃을 기다리지 않음                              │
│     • 빠른 복구 가능                                        │
│                                                             │
└─────────────────────────────────────────────────────────────┘

8. 흐름 제어와 윈도우 크기

슬라이딩 윈도우

┌─────────────────────────────────────────────────────────────┐
│                    슬라이딩 윈도우                           │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  목적:                                                      │
│  • 송신측과 수신측의 처리 속도 차이 조절                    │
│  • 수신 버퍼 오버플로우 방지                                │
│  • 네트워크 효율성 향상                                     │
│                                                             │
│                                                             │
│  동작 원리:                                                 │
│  ─────────────────────────────────────────                  │
│                                                             │
│  송신측 버퍼:                                               │
│  ┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐                    │
│  │✓ │✓ │✓ │1 │2 │3 │4 │ 5│ 6│ 7│ 8│ 9│                    │
│  └──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘                    │
│   ACK됨   │← 전송됨, ACK 대기 →│← 전송 가능 →│             │
│           │                    │             │              │
│           └─────── 윈도우 크기: 6 ────────────┘              │
│                                                             │
│                                                             │
│  수신측이 윈도우 크기 조절:                                 │
│  • 버퍼 여유 많음 → 윈도우 크기 증가 → 빠른 전송           │
│  • 버퍼 부족 → 윈도우 크기 감소 → 전송 속도 감소           │
│  • 버퍼 가득 참 → 윈도우 크기 0 → 전송 중단                 │
│                                                             │
└─────────────────────────────────────────────────────────────┘

윈도우 크기 조절 예시

┌─────────────────────────────────────────────────────────────┐
│                   윈도우 크기 조절 과정                      │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  [송신측]                                  [수신측]         │
│      │                                        │             │
│      │    3-Way Handshake                     │             │
│      │    (Window=4096 광고)                  │             │
│      │←───────────────────────────────────────│             │
│      │                                        │             │
│      │    1000바이트 전송                     │             │
│      ├───────────────────────────────────────→│             │
│      │                                        │ 버퍼: 1000  │
│      │                                        │             │
│      │    1000바이트 전송                     │             │
│      ├───────────────────────────────────────→│             │
│      │                                        │ 버퍼: 2000  │
│      │                                        │             │
│      │           ACK, Window=2096             │             │
│      │←───────────────────────────────────────│ 처리 중...  │
│      │    "2096바이트만 더 받을 수 있어"      │             │
│      │                                        │             │
│      │    1000바이트 전송                     │             │
│      ├───────────────────────────────────────→│             │
│      │                                        │ 버퍼: 2000  │
│      │                                        │             │
│      │    1000바이트 전송                     │             │
│      ├───────────────────────────────────────→│             │
│      │                                        │ 버퍼: 3000  │
│      │                                        │             │
│      │           ACK, Window=0                │             │
│      │←───────────────────────────────────────│ 버퍼 가득!  │
│      │    "잠깐! 더 보내지 마!"               │             │
│      │                                        │             │
│      │    ═══════ 전송 중단 ═══════          │             │
│      │                                        │             │
│      │        (수신측이 데이터 처리 중)       │             │
│      │                                        │             │
│      │           Window Update=2000           │             │
│      │←───────────────────────────────────────│ 버퍼 비움   │
│      │    "2000바이트 받을 수 있어!"          │             │
│      │                                        │             │
│      │    ═══════ 전송 재개 ═══════          │             │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Zero Window와 Probe

┌─────────────────────────────────────────────────────────────┐
│                Zero Window Probe                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  문제 상황:                                                 │
│  • 수신측이 Window=0을 보냄                                 │
│  • 송신측은 전송 중단                                       │
│  • 수신측이 보낸 Window Update가 손실되면?                  │
│  → 양쪽 모두 영원히 대기 (Deadlock!)                        │
│                                                             │
│                                                             │
│  해결: Zero Window Probe                                    │
│  ─────────────────────────────────────────                  │
│                                                             │
│  [송신측]                                  [수신측]         │
│      │                                        │             │
│      │           ACK, Window=0                │             │
│      │←───────────────────────────────────────│             │
│      │                                        │             │
│      │   (일정 시간 후)                       │             │
│      │                                        │             │
│      │    Zero Window Probe (1바이트)         │             │
│      ├───────────────────────────────────────→│             │
│      │    "아직 버퍼 비었어?"                 │             │
│      │                                        │             │
│      │           ACK, Window=1000             │             │
│      │←───────────────────────────────────────│             │
│      │    "응! 1000바이트 받을 수 있어"       │             │
│      │                                        │             │
│      │    ═══════ 전송 재개 ═══════          │             │
│                                                             │
└─────────────────────────────────────────────────────────────┘

9. 실무 활용

TCP 연결 상태 확인

Windows에서 TCP 연결 확인:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

> netstat -an

활성 연결

  프로토콜  로컬 주소              외부 주소              상태
  TCP       0.0.0.0:80             0.0.0.0:0              LISTENING
  TCP       0.0.0.0:443            0.0.0.0:0              LISTENING
  TCP       127.0.0.1:3306         0.0.0.0:0              LISTENING
  TCP       192.168.1.10:52341     142.250.185.78:443     ESTABLISHED
  TCP       192.168.1.10:52342     20.189.173.1:443       TIME_WAIT
  TCP       192.168.1.10:52343     52.109.88.45:443       CLOSE_WAIT


상태별 의미:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

• LISTENING    : 서버가 연결 대기 중
• ESTABLISHED  : 정상 연결 상태
• TIME_WAIT    : 연결 종료 후 대기 중
• CLOSE_WAIT   : 상대방이 연결 종료 요청함 (애플리케이션 종료 필요)
• FIN_WAIT_1/2 : 연결 종료 진행 중
• SYN_SENT     : 연결 요청 보냄
• SYN_RECEIVED : 연결 요청 받음


Linux에서 TCP 연결 확인:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

$ ss -tan
State      Recv-Q Send-Q Local Address:Port  Peer Address:Port
LISTEN     0      128    0.0.0.0:80          0.0.0.0:*
LISTEN     0      128    0.0.0.0:443         0.0.0.0:*
ESTAB      0      0      192.168.1.10:52341  142.250.185.78:443
TIME-WAIT  0      0      192.168.1.10:52342  20.189.173.1:443

$ netstat -tnp
Proto  Recv-Q Send-Q Local Address   Foreign Address  State       PID/Program
tcp    0      0      0.0.0.0:80      0.0.0.0:*        LISTEN      1234/nginx
tcp    0      0      192.168.1.10:52341 142.250.185.78:443 ESTABLISHED 5678/chrome

Wireshark로 TCP 분석

Wireshark에서 3-Way Handshake 분석:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

No.  Time     Source          Destination     Protocol  Info
1    0.0000   192.168.1.10    142.250.185.78  TCP       52341→443 [SYN] Seq=0
2    0.0150   142.250.185.78  192.168.1.10    TCP       443→52341 [SYN, ACK] Seq=0 Ack=1
3    0.0151   192.168.1.10    142.250.185.78  TCP       52341→443 [ACK] Seq=1 Ack=1


패킷 1번 상세:
┌───────────────────────────────────────────────────────────┐
│  Transmission Control Protocol                             │
│  ├─ Source Port: 52341                                    │
│  ├─ Destination Port: 443                                 │
│  ├─ Sequence Number: 0 (relative)                         │
│  ├─ Acknowledgment Number: 0                              │
│  ├─ Header Length: 40 bytes                               │
│  ├─ Flags: 0x002 (SYN)                                    │
│  │   ├─ SYN: Set                                          │
│  │   └─ 나머지: Not set                                   │
│  ├─ Window: 65535                                         │
│  ├─ Checksum: 0x1234                                      │
│  └─ Options:                                              │
│      ├─ MSS: 1460                                         │
│      ├─ SACK Permitted                                    │
│      └─ Window Scale: 8                                   │
└───────────────────────────────────────────────────────────┘


Wireshark 필터:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

• tcp.flags.syn == 1           # SYN 패킷만
• tcp.flags.syn == 1 && tcp.flags.ack == 1  # SYN+ACK만
• tcp.flags.fin == 1           # FIN 패킷만
• tcp.flags.reset == 1         # RST 패킷만
• tcp.analysis.retransmission  # 재전송 패킷
• tcp.analysis.duplicate_ack   # 중복 ACK
• tcp.port == 443              # 443 포트 통신
• ip.addr == 192.168.1.10 && tcp  # 특정 IP의 TCP 통신

일반적인 TCP 문제와 해결

┌─────────────────────────────────────────────────────────────┐
│                  TCP 문제 해결 가이드                        │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. CLOSE_WAIT 상태가 계속 쌓이는 경우                      │
│  ─────────────────────────────────────────                  │
│  원인: 애플리케이션이 소켓을 제대로 close()하지 않음        │
│  해결: 애플리케이션 코드에서 소켓 닫기 확인                 │
│                                                             │
│  확인:                                                      │
│  > netstat -an | find "CLOSE_WAIT"                          │
│                                                             │
│                                                             │
│  2. TIME_WAIT 상태가 너무 많은 경우                         │
│  ─────────────────────────────────────────                  │
│  원인: 짧은 연결이 많이 발생 (예: HTTP 요청)                │
│  해결:                                                      │
│  • 연결 재사용 (Keep-Alive)                                 │
│  • SO_REUSEADDR 옵션 사용                                   │
│  • 커널 파라미터 조정 (Linux)                               │
│                                                             │
│  Linux 커널 파라미터:                                       │
│  $ sysctl -w net.ipv4.tcp_tw_reuse=1                       │
│                                                             │
│                                                             │
│  3. 연결이 자주 끊기는 경우                                 │
│  ─────────────────────────────────────────                  │
│  원인:                                                      │
│  • 방화벽 타임아웃                                          │
│  • 네트워크 불안정                                          │
│  • Keep-Alive 설정 없음                                     │
│                                                             │
│  해결:                                                      │
│  • TCP Keep-Alive 활성화                                    │
│  • 애플리케이션 레벨 하트비트                               │
│                                                             │
│                                                             │
│  4. 연결 지연 (느린 연결)                                   │
│  ─────────────────────────────────────────                  │
│  원인:                                                      │
│  • DNS 지연                                                 │
│  • 네트워크 지연 (높은 RTT)                                 │
│  • 패킷 손실로 인한 재전송                                  │
│                                                             │
│  확인:                                                      │
│  > ping [서버주소]                                          │
│  > tracert [서버주소]                                       │
│                                                             │
│                                                             │
│  5. RST로 연결이 끊기는 경우                                │
│  ─────────────────────────────────────────                  │
│  원인:                                                      │
│  • 서버 포트가 닫혀있음                                     │
│  • 방화벽에서 차단                                          │
│  • 서버 애플리케이션 비정상 종료                            │
│                                                             │
│  확인:                                                      │
│  > telnet [서버주소] [포트]                                 │
│                                                             │
└─────────────────────────────────────────────────────────────┘

핵심 정리

개념설명
TCP 세그먼트TCP 헤더가 붙은 데이터 단위
순서 번호전송하는 데이터의 바이트 순서
확인 응답 번호다음에 받기 기대하는 바이트 번호
SYN연결 시작 요청 플래그
ACK확인 응답 플래그
FIN연결 종료 요청 플래그
RST연결 강제 리셋 플래그
3-Way HandshakeTCP 연결 설정 (SYN → SYN+ACK → ACK)
4-Way HandshakeTCP 연결 종료 (FIN → ACK → FIN → ACK)
TIME_WAIT연결 종료 후 2MSL 동안 대기하는 상태
윈도우 크기수신 가능한 데이터 크기 (흐름 제어)

TCP 연결 과정 요약

┌─────────────────────────────────────────────────────────────┐
│                    TCP 연결 흐름                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. 연결 설정 (3-Way Handshake)                             │
│     ─────────────────────────────────────────               │
│     클라이언트              서버                            │
│         │   SYN (연결할래요!)   │                           │
│         ├─────────────────────→│                            │
│         │   SYN+ACK (좋아요!)  │                            │
│         │←─────────────────────┤                            │
│         │   ACK (시작!)        │                            │
│         ├─────────────────────→│                            │
│                                                             │
│  2. 데이터 전송                                             │
│     ─────────────────────────────────────────               │
│     • Seq/Ack로 순서 보장                                   │
│     • 윈도우로 흐름 제어                                    │
│     • 손실 시 재전송                                        │
│                                                             │
│  3. 연결 종료 (4-Way Handshake)                             │
│     ─────────────────────────────────────────               │
│     클라이언트              서버                            │
│         │   FIN (끝날래요!)    │                            │
│         ├─────────────────────→│                            │
│         │   ACK (잠깐만요)     │                            │
│         │←─────────────────────┤                            │
│         │   FIN (나도 끝!)     │                            │
│         │←─────────────────────┤                            │
│         │   ACK (안녕!)        │                            │
│         ├─────────────────────→│                            │
│         │                      │                            │
│      (TIME_WAIT)          (CLOSED)                          │
│                                                             │
└─────────────────────────────────────────────────────────────┘

주요 명령어 정리

TCP 연결 상태 확인:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Windows:
> netstat -an              # 모든 연결 상태
> netstat -ano             # PID 포함
> netstat -an | find "ESTABLISHED"  # 연결된 것만

Linux:
$ ss -tan                  # TCP 연결 상태
$ ss -tanp                 # 프로세스 정보 포함
$ netstat -tnp             # TCP 연결과 프로세스


포트 확인:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Windows:
> netstat -ano | find "LISTEN"
> netstat -ano | find ":80"

Linux:
$ ss -tlnp                 # LISTEN 중인 TCP 포트
$ lsof -i :80              # 80포트 사용 프로세스


연결 테스트:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

$ telnet [host] [port]     # TCP 연결 테스트
$ nc -zv [host] [port]     # 포트 스캔
$ curl -v [url]            # HTTP 연결 상세

용어 정리

  • TCP (Transmission Control Protocol): 연결 지향형, 신뢰성 있는 전송 계층 프로토콜
  • 세그먼트 (Segment): TCP 헤더가 붙은 데이터 단위
  • 순서 번호 (Sequence Number): 전송하는 데이터의 바이트 순서 번호
  • 확인 응답 번호 (Acknowledgment Number): 다음에 받기 기대하는 바이트 번호
  • 제어 비트 (Control Flags): SYN, ACK, FIN, RST, PSH, URG의 6개 플래그
  • 3-Way Handshake: TCP 연결 설정 과정 (SYN → SYN+ACK → ACK)
  • 4-Way Handshake: TCP 연결 종료 과정 (FIN → ACK → FIN → ACK)
  • TIME_WAIT: 연결 종료 후 2MSL 동안 대기하는 상태
  • MSL (Maximum Segment Lifetime): 패킷이 네트워크에서 생존할 수 있는 최대 시간
  • 윈도우 크기 (Window Size): 수신측이 한 번에 받을 수 있는 데이터 크기
  • 슬라이딩 윈도우 (Sliding Window): 흐름 제어를 위한 윈도우 관리 기법
  • ISN (Initial Sequence Number): 연결 시 사용하는 초기 순서 번호