| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 | 31 |
- 오블완
- LLM
- CKA 기출문제
- kotlin
- golang
- Spring
- docker
- 바이브코딩
- go
- Claude
- AWS EKS
- CKA
- 티스토리챌린지
- 기록으로 실력을 쌓자
- AI
- Java
- kotlin coroutine
- MySQL
- PETERICA
- 공부
- aws
- 정보처리기사 실기 기출문제
- 코틀린 코루틴의 정석
- Network
- Kubernetes
- Rag
- SRE
- tucker의 go 언어 프로그래밍
- CloudWatch
- minikube
- Today
- Total
피터의 개발이야기
[Network] 15. 모든 편지에 수령 확인이 필요할까? 본문

목차: [Network] TCP/IP를 우편 시스템으로 이해하기
TCP/IP를 우편 시스템으로 이해하기 — Part 4. 이름을 주소로 바꾸고 대화를 시작하기
ㅁ 들어가며
IP Address와 Port Number를 알면 어느 Host의 어떤 Application으로 데이터를 보낼지 표현할 수 있다.
이제 남은 질문은 어떻게 보낼 것인가다.
은행 송금 요청처럼 빠짐없이 순서대로 전달되어야 하는 데이터가 있다.
한 부분이라도 사라지면 전체 의미가 달라질 수 있다.
반면 실시간 음성처럼 조금 손실되더라도 오래된 데이터를 기다리는 것보다
최신 데이터를 제때 전달하는 편이 나은 경우도 있다.
모든 데이터를 확인하고 다시 보낼 것인가?
아니면 필요한 정보만 담아 바로 보낼 것인가?
Transport Layer의 대표적인 두 선택이 TCP(Transmission Control Protocol)와 UDP(User Datagram Protocol)다.
흔히 TCP는 느리지만 안전하고 UDP는 빠르지만 불안전하다고 설명한다.
하지만 이 표현만으로는
HTTP/3가 UDP 위의 QUIC을 사용하는 이유,
DNS가 UDP와 TCP를 모두 사용하는 이유,
Application이 UDP 위에서 신뢰성을 구현할 수 있는 이유를 설명하기 어렵다.
이번 글에서는
Byte Stream, Datagram, Reliability, Ordering, Message Boundary, Overhead, Head-of-Line Blocking을 중심으로 TCP와 UDP가 각각 무엇을 제공하고 무엇을 Application에 맡기는지 살펴본다.
ㅁ IP는 배달을 어디까지 약속할까?
IP는 패킷을 목적지 주소 방향으로 전달하는 Best-Effort 서비스다.
경로 중 Packet Loss, 순서 변경, 중복, 지연이 발생할 수 있다.
보낸 순서: Packet 1 → Packet 2 → Packet 3
가능한 도착:
Packet 1 → Packet 3 → Packet 2
Packet 1 → Packet 3
Packet 1 → Packet 2 → Packet 2 → Packet 3
IP 자체는 다음을 End-to-End로 보장하지 않는다.
- 모든 Packet의 도착
- 보낸 순서와 같은 도착 순서
- 중복 없는 전달
- Application이 데이터를 처리했다는 확인
Transport Protocol은 이 불완전한 IP 위에서 Application이 원하는 통신 모델을 제공한다.
TCP는 순서 있는 신뢰 가능한 Byte Stream을 제공하려 한다.
UDP는 최소한의 Transport 정보로 독립적인 Datagram을 전달하고 추가 동작을 Application에 맡긴다.
ㅁ 일반 우편과 등기우편으로만 나누면 충분할까?
우편 비유에서는 UDP를 일반 우편, TCP를 등기우편에 자주 비유한다.
일반 우편은 보내고 끝나며 등기우편은 접수와 수령 과정을 확인한다고 설명하기 쉽다.
하지만 실제 TCP는 편지 한 통씩 수령증을 붙이는 방식과 다르다.
- TCP는 Application Message가 아니라 연속된 Byte Stream을 다룬다.
- 여러 Byte 범위를 묶어 누적 ACK할 수 있다.
- 전송량을 수신자의 여유와 네트워크 혼잡에 맞춘다.
- 손실된 범위를 추론해 재전송한다.
UDP도 무조건 확인할 수 없는 우편은 아니다.
Application이 Sequence Number, ACK, 재전송, 오류 복구를 직접 추가할 수 있다. QUIC이 UDP 위에서 연결과 신뢰성, 혼잡 제어를 구현하는 것이 대표적인 사례다.
따라서 우편 비유의 핵심은 다음 정도로 두는 것이 정확하다.
TCP: 운송 체계가 순서와 재전송을 관리하는 연속 배송 서비스
UDP: 독립된 봉투를 전달하고 추가 규칙은 이용자가 정하는 배송 서비스
ㅁ UDP는 무엇을 담아 보낼까?
UDP는 Application Data를 Datagram 단위로 전달한다.
UDP Header의 기본 크기는 8바이트이며 네 필드로 이루어진다.
| 필드 | 크기 | 역할 |
| Source Port | 16비트 | 보내는 Endpoint의 Port |
| Destination Port | 16비트 | 받을 Endpoint의 Port |
| Length | 16비트 | UDP Header와 Data의 전체 길이 |
| Checksum | 16비트 | 전송 중 손상 탐지 |
UDP Header에는 다음 기능을 위한 필드가 없다.
- 연결 설정 Handshake
- Sequence Number
- Acknowledgment Number
- Receiver Window
- Protocol 자체의 재전송 Timer
UDP는 Datagram을 IP에 넘기고 도착 여부를 기본적으로 추적하지 않는다.
이 단순함은 Header와 상태 관리 부담을 줄이지만, 필요한 신뢰성을 Application이 결정해야 한다는 뜻이기도 하다.
ㅁ UDP Checksum이 있으면 신뢰할 수 있는 것 아닐까?
Checksum은 데이터가 전송 중 손상되었는지 탐지하는 데 도움을 준다.
하지만 Checksum이 다음을 제공하는 것은 아니다.
- 손상된 Datagram의 자동 복구
- 사라진 Datagram의 재전송
- Datagram 순서 정렬
- 중복 Datagram 제거
- 보낸 상대의 신원 인증
Checksum 검증에 실패하면 Datagram은 폐기될 수 있지만 UDP가 새 Datagram을 요청하지는 않는다.
IPv4 UDP에서는 Checksum 값 0으로 미사용을 표현할 수 있다.
IPv6 UDP Checksum은 일반적으로 필수이며 일부 제한적인 예외는 별도 규격과 환경에 따른다.
TCP와 UDP의 Checksum도 암호학적 무결성과 인증을 제공하는 기능이 아니다.
의도적인 변조와 도청을 막으려면 TLS, DTLS, QUIC 같은 보안 계층이 필요하다.
ㅁ Datagram은 편지 한 통의 경계를 기억한다
Application이 UDP Socket에 세 번 데이터를 보냈다고 하자.
send: "ABC"
send: "DEFG"
send: "HI"
UDP는 각각을 독립된 Datagram으로 다룬다.
정상 도착했다면 수신 Application은 세 Datagram의 경계를 구분해 받을 수 있다.
recv: "ABC"
recv: "DEFG"
recv: "HI"
이를 Message Boundary를 보존한다고 표현한다.
다만 수신 Buffer가 Datagram보다 작으면 나머지 부분이 잘리거나 API별 동작이 달라질 수 있다. 큰 UDP Datagram은 IP Fragmentation과 손실 위험도 키울 수 있다.
각 Datagram은 독립적이므로 다음처럼 도착할 수 있다.
"DEFG" → "ABC" → "HI"
또는 하나가 사라질 수 있다.
"ABC" → "HI"
UDP Protocol은 이를 원래 순서로 재배치하거나 누락을 자동으로 채우지 않는다.
ㅁ TCP는 편지보다 긴 종이 두루마리에 가깝다
TCP는 Application에 Ordered Byte Stream을 제공한다.
Application이 다음처럼 데이터를 써도 수신 측의 읽기 단위가 그대로 일치한다고 보장하지 않는다.
Sender write 1: "ABC"
Sender write 2: "DEFG"
가능한 Receiver read:
"ABCDEFG"
또는
"AB"
"CDE"
"FG"
TCP는 Byte의 순서는 보존하지만 Application Message의 경계는 보존하지 않는다.
따라서 TCP 위의 Application Protocol은 메시지 경계를 스스로 표현해야 한다.
- 고정 길이 Header
- Length Prefix
- 줄바꿈이나 특정 Delimiter
- HTTP처럼 Header와 Content-Length, Chunked Encoding 등의 규칙
TCP를 사용한다고 Application Message가 자동으로 한 번의 read에 온전히 도착하는 것은 아니다.
이 점을 놓치면 TCP Stream에서 Message가 합쳐지거나 나뉘는 현상을 Packet 오류로 오해할 수 있다.
ㅁ TCP Header에는 어떤 약속이 들어 있을까?
Option이 없는 TCP Header의 최소 크기는 20바이트다.
대표적인 필드는 다음과 같다.
| 필드 | 역할 |
| Source / Destination Port | 양쪽 Application Endpoint 식별 |
| Sequence Number | Byte Stream에서 Segment Data의 위치 표현 |
| Acknowledgment Number | 다음에 받기를 기대하는 Byte 위치 표현 |
| Data Offset | TCP Header 길이 표시 |
| Flags | SYN, ACK, FIN, RST 등 연결 상태 제어 |
| Window Size | 수신 가능한 Byte 범위 광고 |
| Checksum | Header와 Data 손상 탐지 |
| Options | MSS, Window Scale, SACK 관련 정보 등 |
TCP는 이 정보를 사용해 다음 기능을 제공한다.
- Connection Establishment와 종료
- Byte 순서 정렬
- ACK와 재전송을 통한 신뢰성
- 중복 Byte 처리
- Receiver 능력에 맞춘 Flow Control
- Network 혼잡에 맞춘 Congestion Control
이 기능들은 Header 12바이트 차이만의 문제가 아니다.
양 끝이 Connection State, Buffer, Timer, Sequence Space와 혼잡 상태를 관리해야 한다.
TCP의 Overhead는 Packet Header 크기뿐 아니라 연결 설정과 상태 관리, ACK, 재전송, 제어 알고리즘을 포함한다.
ㅁ TCP의 신뢰성은 무엇을 보장할까?
TCP가 신뢰 가능하다는 말은 일반적으로 다음 의미다.
연결이 유지되는 동안
상대 TCP가 전달한 Byte를
중복 없이 순서대로
Application이 읽을 수 있는 Stream에 제공한다.
그러나 TCP ACK가 다음 사실까지 보장하는 것은 아니다.
- 사용자가 화면에서 내용을 보았다.
- Server Application이 업무 처리를 완료했다.
- Database Transaction이 Commit되었다.
- 요청이 정확히 한 번만 비즈니스에 반영되었다.
TCP ACK는 Transport Layer의 수신 상태를 나타낸다.
Application 처리 완료 확인이 아니다.
예를 들어 결제 요청의 Byte가 Server에 도착한 뒤 응답 전에 연결이 끊기면 Client는 결제가 처리되었는지 알기 어렵다.
무작정 재시도하면 중복 결제가 생길 수 있다.
이 문제는 Application Protocol의 응답, Idempotency Key, Transaction 상태 조회 같은 별도의 설계로 해결해야 한다.
TCP Reliability ≠ Exactly-Once Business Processing
ㅁ UDP는 빠르고 TCP는 느리다는 말은 항상 맞을까?
UDP에는 TCP Handshake와 기본 재전송, 순서 정렬, Flow/Congestion Control이 없다.
작은 질의 하나를 즉시 보내는 상황에서는 적은 제어 절차가 장점이 될 수 있다.
하지만 UDP를 사용한다고 Application이 자동으로 빨라지는 것은 아니다.
신뢰성, 혼잡 제어, 보안을 Application이 모두 구현해야 한다면 복잡성과 제어 Traffic이 다시 생긴다.
TCP도 이미 연결된 상태에서는 지속적으로 데이터를 효율적으로 전송할 수 있고 운영체제에 오랫동안 최적화되어 있다.
실제 성능은 다음 요소의 영향을 받는다.
- 연결이 새로 필요한가, 재사용할 수 있는가?
- 손실률과 RTT는 얼마인가?
- 데이터 크기와 메시지 빈도는 어떤가?
- 순서 보장이 필요한가?
- Application이 재전송과 혼잡 제어를 어떻게 구현했는가?
- TLS와 Protocol Handshake가 몇 번 필요한가?
- Kernel과 NIC Offload가 어떤 처리를 지원하는가?
따라서 선택 기준은 단순한 속도 서열이 아니다.
TCP: 공통 신뢰성과 Stream 모델을 Transport가 제공
UDP: 최소 Datagram 모델 위에서 Application이 필요한 기능을 선택
ㅁ 한 조각이 사라지면 뒤의 데이터도 기다려야 할까?
TCP는 Byte를 순서대로 Application에 제공한다.
다음 Segment 중 두 번째가 사라졌다고 하자.
Segment 1 도착
Segment 2 손실
Segment 3 도착
Segment 4 도착
수신 TCP는 뒤의 Byte를 Buffer에 보관할 수 있지만 빠진 Byte가 복구되기 전에는 순서대로 Application에 전달하지 못할 수 있다.
이를 TCP Stream의 Head-of-Line(HOL) Blocking이라고 한다.
하나의 TCP 연결 위에서 여러 논리적 요청을 Multiplexing하는 Protocol은
앞선 Byte 손실 때문에 뒤의 응답도 영향을 받을 수 있다.
QUIC은 UDP 위에서 신뢰성, 암호화, 혼잡 제어와 여러 독립 Stream을 구현한다.
하나의 QUIC Stream에서 손실이 발생해도 다른 Stream의 Application Data 전달까지 TCP 연결 전체처럼 막지 않도록 설계되었다.
다만 QUIC도 손실된 Packet에 있던 해당 Stream Data를 복구해야 하며,
네트워크 혼잡과 재전송의 영향이 사라지는 것은 아니다.
UDP가 해결한 것이 아니라 UDP의 최소 기능 위에서 QUIC이 다른 신뢰성 모델을 구현한 것이다.
ㅁ 어떤 Application이 UDP를 선택할까?
UDP가 어울릴 수 있는 상황은 다음과 같다.
ㅇ 작은 질문과 짧은 응답
전통적인 DNS 질의처럼 작은 Request와 Response가 중심인 경우 연결 설정을 줄일 수 있다. 다만 DNS도 큰 응답과 Zone Transfer 등에서는 TCP를 사용한다.
ㅇ 최신 데이터의 시간이 중요한 실시간 통신
Voice와 Video에서 너무 늦게 도착한 오래된 Frame은 재생 가치가 낮을 수 있다. Application은 일부 손실을 허용하고 Jitter Buffer, 선택적 복구, Codec의 오류 은폐를 사용할 수 있다.
ㅇ Application이 독자적인 신뢰성 모델을 원하는 경우
QUIC은 UDP 위에서 Stream별 신뢰성, 연결 이동, 혼잡 제어를 구현한다.
ㅇ Multicast 또는 Broadcast가 필요한 경우
UDP는 IP Multicast와 Broadcast Datagram에 사용할 수 있다. TCP는 두 Endpoint 사이의 연결 기반 Unicast Protocol이다.
UDP 사용이 곧 Packet Loss를 무시한다는 뜻은 아니다.
Application이 자신의 목적에 맞는 손실 처리와 혼잡 제어를 책임진다는 뜻이다.
ㅁ 어떤 Application이 TCP를 선택할까?
TCP가 어울릴 수 있는 상황은 다음과 같다.
ㅇ 모든 Byte를 순서대로 받아야 하는 경우
파일 전송, 원격 터미널, 일반적인 Database 연결처럼 누락된 Byte를 그대로 허용하기 어려운 통신이다.
ㅇ 공통의 재전송과 혼잡 제어를 활용하려는 경우
Application마다 신뢰성과 네트워크 공정성을 새로 구현하지 않고 운영체제의 TCP Stack을 사용할 수 있다.
ㅇ Stream 기반 Protocol인 경우
HTTP/1.1, HTTP/2, TLS 기반의 많은 Application Protocol이 TCP Byte Stream 위에서 동작한다.
TCP를 선택해도 Application Timeout, 요청 재시도, 업무 중복 방지, 보안은 별도로 설계해야 한다.
Transport가 제공하는 신뢰성과 Application이 필요로 하는 신뢰성의 범위를 구분해야 한다.
ㅁ TCP와 UDP는 보안을 제공할까?
TCP의 연결과 ACK는 상대의 Application 신원을 인증하거나 내용을 암호화하지 않는다.
UDP의 Checksum도 공격자에 의한 변조를 막는 암호학적 보호가 아니다.
TCP/UDP가 제공하지 않는 것
├─ 기밀성
├─ 상대 신원 인증
└─ 암호학적 무결성
TCP 위에서는 TLS를, UDP Datagram 기반 Application에서는 DTLS를 사용할 수 있다.
QUIC은 TLS 1.3 Handshake를 통합해 보안 연결을 만든다.
Port 443을 사용하거나 TCP로 연결되었다는 사실만으로 Traffic이 안전하다고 판단할 수 없다.
ㅁ 우편 비유를 네트워크 용어로 바꾸면
지금까지의 장면을 실제 네트워크 용어와 연결하면 다음과 같다.
| 우편 시스템의 모습 | 네트워크 용어 | 의미 |
| 독립된 봉투 한 장 | UDP Datagram | Message Boundary가 있는 독립적인 전송 단위 |
| 이어 붙인 긴 종이 두루마리 | TCP Byte Stream | Message Boundary 없이 순서 있는 Byte의 흐름 |
| 봉투 번호와 수령 확인 | Sequence Number / ACK | Byte 위치와 수신 범위를 추적하는 TCP 정보 |
| 사라진 내용을 다시 발송 | Retransmission | 손실로 판단한 Data를 다시 보내는 동작 |
| 받는 창구의 남은 공간 안내 | Flow Control | Receiver Buffer에 맞춰 전송량을 조절 |
| 도로 혼잡에 맞춘 발송량 조절 | Congestion Control | Network 상태에 맞춰 In-flight Data를 조절 |
| 앞의 종이가 빠져 뒤도 읽지 못함 | Head-of-Line Blocking | 손실된 Byte 복구 전 뒤의 Stream 전달이 지연 |
| 필요한 배송 규칙을 이용자가 직접 추가 | Application-Level Reliability | UDP 위에서 ACK·재전송 등을 Application이 구현 |
TCP와 UDP의 기본 차이는 다음처럼 정리할 수 있다.
| 항목 | TCP | UDP |
| 통신 모델 | Connection-oriented Byte Stream | Connectionless Datagram |
| Message Boundary | 보존하지 않음 | 보존 |
| 순서 보장 | Byte 순서 제공 | Protocol이 제공하지 않음 |
| 손실 복구 | ACK와 재전송 제공 | Protocol이 제공하지 않음 |
| Flow/Congestion Control | 제공 | Application에 맡김 |
| 기본 Header | 최소 20바이트 | 8바이트 |
| Multicast/Broadcast | 지원하지 않음 | 가능 |
ㅁ 직접 Header와 전달 단위를 관찰해 보기
Linux에서 TCP와 UDP Socket을 구분해 본다.
ss -tn
ss -uan
Packet Capture에서 두 Protocol의 Header를 비교할 수 있다.
sudo tcpdump -n -vv -i eth0 'tcp or udp'
특정 Port만 보고 싶다면 다음처럼 Filter를 좁힌다.
sudo tcpdump -n -vv -i eth0 'tcp port 8080 or udp port 8081'
TCP 출력에서는 다음 항목을 찾아본다.
Flags, Sequence Number, Acknowledgment, Window, Options
UDP 출력에서는 다음 항목을 비교한다.
Source Port, Destination Port, Length, Checksum
개인 개발 환경에서 nc로 UDP Datagram을 주고받을 수 있다.
구현마다 Listen 옵션 문법이 다를 수 있다.
수신 Terminal:
nc -u -l 8081
송신 Terminal:
nc -u 127.0.0.1 8081
UDP는 TCP처럼 Handshake로 연결 상태를 만들지 않는다는 점을 ss -uan과 Packet Capture에서 확인한다.
운영체제 Socket API에서 connect한 UDP Socket은 Peer가 표시될 수 있지만 TCP Handshake가 수행되었다는 뜻은 아니다.
Loopback Interface를 관찰할 때 Linux에서는 보통 lo, macOS에서는 보통 lo0를 사용한다.
실제 Interface 이름은 시스템에서 확인한다.
ㅁ 핵심 정리
- IP는 Packet의 도착, 순서, 중복 없는 전달을 End-to-End로 보장하지 않는 Best-Effort Protocol이다.
- UDP는 8바이트 Header로 독립된 Datagram을 전달하고 Message Boundary를 보존한다.
- UDP Protocol은 연결 설정, 순서 정렬, ACK, 재전송, Flow/Congestion Control을 기본 제공하지 않는다.
- TCP는 연결 상태를 관리하며 순서 있는 신뢰 가능한 Byte Stream을 제공한다.
- TCP는 Byte 순서는 보존하지만 Application Message Boundary는 보존하지 않는다.
- TCP ACK는 상대 Application의 업무 처리 완료나 Exactly-Once 처리를 보장하지 않는다.
- UDP라고 항상 빠르고 TCP라고 항상 느린 것은 아니며 필요한 기능과 환경을 함께 비교해야 한다.
- TCP Stream은 손실된 Byte 때문에 뒤의 Data 전달도 지연되는 HOL Blocking을 겪을 수 있다.
- QUIC은 UDP 위에서 필요한 신뢰성, 보안, 혼잡 제어와 독립 Stream을 구현한다.
- TCP와 UDP의 Checksum은 암호화나 신원 인증을 제공하지 않는다.
핵심 용어: Best-Effort, TCP, UDP, Byte Stream, Datagram, Message Boundary, Sequence Number, Acknowledgment, Retransmission, Reliability, Ordering, Flow Control, Congestion Control, Head-of-Line Blocking, QUIC, TLS, DTLS
TCP와 UDP의 차이는 안전과 속도의 단순한 선택이 아니다.
공통 신뢰성을 Transport가 맡을지, 목적에 맞는 규칙을 Application이 선택할지의 차이다.
ㅁ 다음 이야기
TCP는 Byte Stream의 순서와 손실 복구를 관리한다.
하지만 데이터를 보내기 전에 양쪽이 서로 보내고 받을 준비가 되었는지, Sequence Number를 어디에서 시작할지 합의해야 한다.
왜 두 번이 아니라 세 번의 메시지가 필요할까?
다음 글에서는 「대화를 시작하기 전에 왜 세 번이나 인사할까?」라는 질문을 통해
TCP State, SYN, SYN-ACK, ACK, Initial Sequence Number와 3-Way Handshake를 살펴본다.
'DevOps > Network' 카테고리의 다른 글
| [Network] 17. 편지가 사라졌다는 사실은 어떻게 알아챌까? (0) | 2026.07.20 |
|---|---|
| [Network] 16. 대화를 시작하기 전에 왜 세 번이나 인사할까? (1) | 2026.07.19 |
| [Network] 14. 한 컴퓨터의 여러 프로그램은 편지를 어떻게 나눠 받을까? (0) | 2026.07.19 |
| [Network] 13. 우리는 왜 숫자 대신 이름으로 접속할까? (0) | 2026.07.19 |
| [Network] 12. 길이 바뀌면 지도는 어떻게 새로 그려질까? (1) | 2026.07.16 |
