"TCP는 연결 지향이고 신뢰성 있고, UDP는 비연결이고 빠릅니다" — 여기서 한 발 더 들어가면, 왜 handshake가 3번인지, TIME_WAIT는 왜 필요한지가 보입니다.

TCP의 신뢰성은 공짜가 아닙니다. handshake, 흐름 제어, 혼잡 제어 — 각각이 어떤 문제를 해결하는지 인과 흐름으로 정리합니다.


TCP vs UDP 한눈에

TCPUDP
연결연결 지향 (handshake)비연결
신뢰성재전송, 순서 보장보장 안 함
속도상대적으로 느림빠름
헤더 크기20~60바이트8바이트
흐름/혼잡 제어있음없음
용도HTTP, SSH, FTP, 이메일DNS, 스트리밍, 게임, VoIP

3-Way Handshake

TCP 연결을 수립하는 과정입니다.

PLAINTEXT
클라이언트                    서버
    │                          │
    │──── SYN (seq=x) ────────→│  1단계: "연결하고 싶어요"
    │                          │
    │←── SYN+ACK (seq=y, ack=x+1) ──│  2단계: "좋아요, 나도 연결할게요"
    │                          │
    │──── ACK (ack=y+1) ──────→│  3단계: "확인, 시작합시다"
    │                          │

왜 3번인가? 2번이면 안 되나?

2번이면 **서버가 클라이언트의 수신 능력을 확인할 수 없습니다 **.

시나리오를 생각해보면:

  1. 클라이언트가 SYN 전송 (오래된 요청이 네트워크에서 지연됨)
  2. 서버가 SYN+ACK 응답
  3. 2-way면 여기서 연결 수립 → 근데 클라이언트는 이미 그 연결을 안 원함

3번째 ACK가 있어야 클라이언트가 "네, 저 진짜 연결 원해요"를 확인시켜줍니다.

또한, 양쪽 모두 ** 시퀀스 번호를 교환 **해야 하는데, SYN으로 자기 시퀀스 번호를 알리고 ACK로 상대의 시퀀스 번호를 확인합니다. 양방향으로 이걸 하려면 최소 3번이 필요합니다.


4-Way Handshake (연결 종료)

PLAINTEXT
클라이언트                    서버
    │                          │
    │──── FIN ────────────────→│  1: "나 보낼 거 다 보냈어"
    │                          │
    │←── ACK ─────────────────│  2: "알겠어, 근데 나는 아직 보낼 게 있어"
    │                          │
    │←── FIN ─────────────────│  3: "나도 다 보냈어"
    │                          │
    │──── ACK ────────────────→│  4: "알겠어, 끊자"
    │                          │
    │   TIME_WAIT (2MSL)       │

왜 4번인가?

종료는 한쪽이 먼저 끊을 수 있으니까 ** 반이중(half-close)**을 지원합니다. 클라이언트가 FIN을 보내도 서버는 아직 보낼 데이터가 있을 수 있습니다. 그래서 ACK와 FIN이 분리되어 4번이 됩니다.

TIME_WAIT은 왜 필요한가

마지막 ACK가 유실되면 서버가 FIN을 재전송합니다. TIME_WAIT 상태에서 이 재전송을 받아서 다시 ACK를 보낼 수 있습니다. 보통 2MSL(Maximum Segment Lifetime, 약 60초) 동안 유지됩니다.

서버에서 TIME_WAIT이 많이 쌓이면 포트 고갈이 발생할 수 있습니다. 이건 실무에서 꽤 자주 겪는 문제입니다.


흐름 제어 (Flow Control)

수신자가 처리할 수 있는 속도에 맞춰 송신자의 전송 속도를 조절하는 메커니즘입니다.

슬라이딩 윈도우

수신자가 ** 윈도우 크기(receive window)**를 알려줍니다. "나 지금 버퍼에 이만큼 여유 있어"라는 뜻입니다.

PLAINTEXT
송신자: 윈도우 크기만큼 ACK 없이 연속 전송 가능
수신자: 처리한 만큼 윈도우를 슬라이드하여 새로운 공간 알림

[전송 완료 | 전송 중 (윈도우) | 전송 대기]

윈도우 크기가 0이 되면 송신자는 전송을 멈춥니다.


혼잡 제어 (Congestion Control)

흐름 제어가 수신자 보호라면, 혼잡 제어는 ** 네트워크 보호 **입니다.

Slow Start

처음에 윈도우 크기를 1에서 시작해서 ACK를 받을 때마다 2배씩 늘립니다. 지수적으로 증가하다가 임계값(ssthresh)에 도달하면 선형 증가로 전환합니다.

PLAINTEXT
윈도우: 1 → 2 → 4 → 8 → 16 (ssthresh) → 17 → 18 → 19 ...
         [지수 증가]              [선형 증가 (혼잡 회피)]

패킷 유실이 감지되면 윈도우를 줄입니다. 어떻게 줄이느냐에 따라 알고리즘이 다릅니다 (Tahoe, Reno, CUBIC 등).


심화 개념

"HTTP는 TCP 위에서 동작하는데, HTTP/3은 왜 UDP를 쓰나요?"

HTTP/3은 QUIC 프로토콜 위에서 동작하는데, QUIC는 UDP 기반입니다.

TCP의 문제점 때문입니다:

  • Head-of-Line Blocking: TCP는 패킷 순서를 보장하니까, 하나가 유실되면 뒤의 모든 패킷이 대기
  • **handshake 오버헤드 **: TCP 3-way + TLS 1.3 handshake = 최소 2 RTT

QUIC는 UDP 위에서 신뢰성과 흐름 제어를 ** 직접 구현 **하되, 스트림별로 독립적으로 관리해서 HOL Blocking을 해결합니다. 그리고 연결 수립과 TLS를 합쳐서 1 RTT 로 줄입니다.

"TCP keepalive와 HTTP keepalive의 차이는?"

  • TCP keepalive: 연결이 살아있는지 주기적으로 빈 패킷을 보내서 확인 (OS 레벨)
  • HTTP keepalive (persistent connection): 하나의 TCP 연결로 여러 HTTP 요청/응답을 주고받음

HTTP/1.0은 요청마다 TCP 연결을 새로 맺었는데, HTTP/1.1부터 Connection: keep-alive가 기본이 되어서 연결을 재사용합니다.

"DNS는 왜 UDP를 쓰나요?"

DNS 쿼리는 보통 하나의 작은 패킷으로 끝납니다. TCP의 3-way handshake 오버헤드가 필요 없죠. 빠르게 질의하고 빠르게 응답받으면 됩니다.

다만, 응답이 512바이트를 초과하거나 zone transfer(영역 전송)를 할 때는 TCP를 사용 합니다.


파생되는 개념들

  • HTTP/1.1 vs HTTP/2 vs HTTP/3 — 프로토콜 진화
  • TLS/SSL 핸드셰이크 — HTTPS의 동작 원리
  • OSI 7계층 / TCP/IP 4계층 — 네트워크 계층 모델
  • NAT, 서브넷, CIDR — IP 주소 관리
  • ** 로드 밸런싱** — L4 vs L7 로드 밸런서의 차이
댓글 로딩 중...