1. TCP와 UDP는 왜 필요한가?
우리가 브라우저에서 서버의 API를 호출한다고 생각해보자
브라우저 → HTTP 요청 → TCP → IP → Wi-Fi / Ethernet → 인터넷 → 서버
여기서 각각 역할은 아래와 같다.
HTTP
"GET /users를 요청할게"
↓
TCP
"이 데이터를 상대 프로세스까지 순서대로 안전하게 전달할게"
↓
IP
"어느 컴퓨터로 보낼지 찾아낼게"
여기서 TCP와 UDP는 전송 계층(Transport Layer)의 대표적인 프로토콜이다.
전송 계층이란?
IP가 데이터를 목적지 컴퓨터까지 전달한다면, 전송 계층은 그 컴퓨터 안의 어떤 프로세스에 데이터를 전달할 것인지를 담당한다.
여기서 프로세스는 쉽게 말하면 현재 실행 중인 프로그램이라고 생각하면 된다.
예를 들어 하나의 서버 컴퓨터에서 다음과 같은 프로그램이 동시에 실행될 수 있다.
8080 → Spring Boot
5432 → PostgreSQL
6379 → Redis
이를 구분하기 위해 사용하는 것이 Port 번호이다.
IP → 어떤 컴퓨터인가?
Port → 그 컴퓨터의 어떤 프로그램과 통신할 것인가?
전송 계층은 이렇게 Port를 이용해 프로세스 간 통신을 지원한다. TCP의 경우 여기에 연결 관리, 신뢰성 있는 전송, 흐름 제어, 혼잡 제어 등의 기능도 제공한다.
그런데 왜 TCP와 UDP 두 종류가 필요할까?
모든 네트워크 데이터의 요구사항은 같지 않다.
예를 들어 생각해보자.
은행 송금 데이터의 경우,"10만원 송금" 데이터가 중간에 사라지면 안된다.
또한, 순서가 중요한 데이터의 경우 "1 → 2 → 3"이 "3 → 1 → 2"로 도착하면 곤란하다.
위와 같은 경우는 정확성이 중요하다.
반면, 온라인 게임에서 캐릭터 위치 데이터를 생각해보자.
10:00:00 → x=100
10:00:01 → x=110
10:00:02 → x=120
위와 같은 위치 데이터가 있을 때, x=110이 유실되었다고 해도 최신 데이터인 x=120가 도착했다면, 굳이 과거 데이터를 다시 받아오기 위해 기다리는 것이 좋은 것은 아닐 가능성이 높다.
즉 어떤 데이터는 정확한 과거 데이터가 중요하고, 어떤 데이터는 빠르게 도착하는 최신 데이터가 중요하다.
이러한 서로 다른 요구사항을 처리하기 위해 성격이 다른 TCP와 UDP가 사용된다.
2. TCP란?
**TCP(Transmission Control Protocol)**는 연결지향적이며, 순서가 보장되는 신뢰성 있는 데이터 전송을 제공하는 프로토콜이다.
대표적인 특징은 다음과 같다.
- 연결 지향(Connection-Oriented)
- 신뢰성 있는 데이터 전송
- 순서 보장
- 손실 데이터 재전송
- 흐름 제어(Flow Control)
- 혼잡 제어(Congestion Control)
- 전이중(Full-Duplex) 통신
- Byte Stream 방식
2.1 연결 지향적이라는 것은 무엇일까?
연결 지향(Connection-Oriented)이라는 표현에서 말하는 연결은 통신하려는 양쪽이 데이터를 보내기 전에 논리적인 연결 상태를 만들고, 통신이 끝날 때까지 그 상태를 관리한다는 의미이다.
예를 들어 브라우저와 웹 서버가 TCP로 통신한다면 TCP는 연결마다 다음과 같은 정보를 관리한다.
현재 어떤 Sequence Number까지 보냈는가?
어디까지 ACK를 받았는가?
상대방이 얼마나 더 받을 수 있는가?
현재 연결이 수립된 상태인가?
종료 중인 상태인가?
즉 TCP는 단순히
데이터 보내기 → 끝
이 아니라,
연결 설정
↓
연결 상태 유지
↓
데이터 송수신
↓
연결 종료
과정을 거친다.
이때 연결을 설정하는 과정이 3-way Handshake이고, 일반적인 정상 종료 과정이 4-way Handshake이다.
2.2 TCP의 ‘신뢰성’은 무엇을 의미할까?
네트워크에서는 데이터가 항상 완벽하게 전달되는 것이 아니다.
데이터가 유실될 수 있음
순서가 바뀔 수 있음
같은 데이터가 중복될 수 있음
전송 중 데이터가 손상될 수 있음
TCP는 이러한 문제를 처리하기 위해 여러 기능을 사용한다.
순서 확인
→ Sequence Number
수신 확인
→ ACK
데이터 유실
→ 재전송
데이터 오류
→ Checksum
따라서 TCP의 신뢰성이란 어떤 상황에서도 무조건 전송에 성공한다는 의미가 아니라, 연결 안에서 손실 복구와 순서 제어 등을 제공하여 애플리케이션에 순서가 맞는 데이터 스트림을 제공한다는 의미이다.
Sequence Number
TCP는 데이터의 위치와 순서를 확인하기 위해 Sequence Number를 사용한다.
예를 들어 SEQ=1000부터 100바이트를 보냈다면,
SEQ = 1000
Data = 100 bytes
해당 데이터는 1000~1099에 해당하고 다음 데이터는 1100부터 시작한다.
이렇게 번호가 있기 때문에 TCP는 데이터가 빠지거나 순서가 바뀐 것을 판단할 수 있다.
ACK
**ACK(Acknowledgment)**는 수신자가 어디까지 데이터를 정상적으로 받았는지 알려주는 확인 응답이다.
Client Server
SEQ=1000, 100 bytes
----------------------------->
ACK=1100
<-------------------------------
ACK=1100은
1099까지 받았으므로 다음에는 1100부터 보내주세요.
라는 의미이다.
재전송
ACK가 일정 시간 동안 오지 않는 등 데이터 손실이 감지되면 TCP는 해당 데이터를 다시 전송한다.
데이터 전송
↓
ACK가 오지 않음
↓
손실로 판단
↓
재전송
또한 같은 ACK가 반복되는 경우 Timeout을 기다리지 않고 빠르게 재전송하는 Fast Retransmit도 사용할 수 있다.
단, TCP에서 ACK를 받았다는 것이 꼭 상대 애플리케이션의 업무 처리가 성공했다는 의미는 아니다.
TCP 데이터 전달 성공
≠
결제 / DB 처리 성공
TCP는 어디까지나 전송 계층에서의 데이터 전달을 담당한다.
2.3 3-way Handshake
Handshake는 본격적인 통신 전에 양쪽이 필요한 정보를 주고받으며 상태를 맞추는 과정이다.
TCP에서는 연결을 설정하기 위해 3-way Handshake를 수행한다.
여기서 주로 사용하는 TCP 제어 플래그는 SYN과 ACK이다.
-
SYN(Synchronize): 연결을 시작하고 Sequence Number를 동기화하기 위한 플래그
-
ACK(Acknowledgment): 상대가 보낸 정보를 정상적으로 받았음을 알리는 플래그
과정은 다음과 같다.
Client Server
SYN (seq=x)
-------------------------------->
SYN + ACK
(seq=y, ack=x+1)
<--------------------------------
ACK (ack=y+1)
-------------------------------->
ESTABLISHED
① SYN
클라이언트가 자신의 초기 Sequence Number인 **ISN(Initial Sequence Number)**과 함께 연결 요청을 보낸다.
"연결하고 싶습니다."
② SYN + ACK
서버는 클라이언트의 SYN을 받았다는 ACK와 자신의 SYN을 함께 보낸다.
"네 요청을 받았고, 나도 연결할 준비가 됐습니다."
③ ACK
클라이언트가 서버의 SYN도 정상적으로 받았다는 ACK를 보낸다.
이후 양쪽 모두 ESTABLISHED 상태가 되어 데이터를 주고받을 수 있다.
왜 2-way가 아니라 3-way일까?
단순하게 생각하면 다음과 같다.
Client
"내 말 들려?"
↓
Server
"응. 내 말도 들려?"
↓
Client
"응. 잘 들려."
조금 더 정확하게는 다음 목적이 있다.
-
양방향 통신이 가능한지 확인
-
양측의 초기 Sequence Number(ISN) 동기화
-
과거에 지연된 중복 연결 요청이 새로운 연결로 잘못 처리되는 것을 방지
따라서 3-way Handshake는 단순히 순서를 외우기보다는 양쪽의 TCP 연결 상태와 Sequence Number를 맞추는 과정이라고 이해하는 것이 중요하다.
2.4 4-way Handshake
통신이 끝나면 TCP 연결도 종료해야 한다.
정상적인 TCP 연결 종료에서는 주로 FIN 플래그를 사용한다.
**FIN(Finish)**은
"나는 이제 이 방향으로 더 이상 보낼 데이터가 없습니다."
라는 의미이다.
일반적인 종료 과정은 다음과 같다.
Client Server
FIN
------------------------------>
ACK
<------------------------------
FIN
<------------------------------
ACK
------------------------------>
왜 3-way가 아니라 4-way일까?
TCP는 Full-Duplex(전이중) 통신을 지원한다.
전이중이란 하나의 TCP 연결에서 양쪽이 동시에 데이터를 보낼 수 있다는 의미이다.
Client --------> Server
데이터
Client <-------- Server
데이터
따라서 Client가 FIN을 보냈다고 해서 Server도 즉시 데이터 전송을 끝내야 하는 것은 아니다.
Server는 우선 ACK를 보내고, 남아 있는 데이터를 모두 전송한 뒤 자신의 FIN을 보낼 수 있다.
Client FIN
↓
Server ACK
↓
남은 데이터 전송
↓
Server FIN
↓
Client ACK
이처럼 한쪽 방향의 전송만 먼저 종료되는 것을 Half-Close라고 한다.
2.5 TIME_WAIT과 CLOSE_WAIT
TCP 연결 종료와 함께 자주 등장하는 상태이다.
TIME_WAIT
마지막 ACK를 보낸 측은 바로 연결 정보를 삭제하지 않고 일정 시간 TIME_WAIT 상태에 머문다.
주요 이유는 두 가지이다.
첫째, 마지막 ACK가 유실되면 상대방이 FIN을 다시 보낼 수 있기 때문에 다시 ACK할 수 있도록 하기 위해서이다.
둘째, 이전 연결에서 늦게 도착한 데이터가 새로운 연결에 영향을 주는 것을 방지하기 위해서이다.
TCP에서는 전통적으로 이를 MSL(Maximum Segment Lifetime) 대기라고 설명한다.
TCP 세그먼트가 네트워크에 존재할 수 있는 최대 시간을 MSL라고 부르고, 일반적으로 TIME_WAIT 상태에서는 2MSL만큼 대기한다.
CLOSE_WAIT
상대에게 FIN을 받아 ACK는 보냈지만 자신의 애플리케이션이 아직 연결을 완전히 닫지 않은 상태이다.
따라서 서버에서 CLOSE_WAIT이 계속 많이 남아 있다면 연결 종료 누락이나 자원 정리 문제 등을 의심해볼 수 있다.
2.6 TCP의 Byte Stream
TCP는 데이터를 Byte Stream으로 처리한다.
Stream은 데이터를 개별 메시지가 아니라 연속된 바이트의 흐름으로 본다는 의미이다.
예를 들어 애플리케이션이
send("HELLO")
send("WORLD")
라고 두 번 보냈다고 해서 수신자가 반드시
HELLO
WORLD
두 번으로 나누어 받는 것은 아니다.
HELLOWORLD
한 번으로 받을 수도 있고,
HEL
LOWORLD
처럼 나누어 받을 수도 있다.
즉, TCP가 보장하는 것은 바이트의 순서이지 애플리케이션이 보낸 메시지의 경계가 아니다.
TCP의 Byte Stream으로 인해 TCP 기반 애플리케이션에서는 메시지의 시작과 끝을 구분하기 위해 Length Prefix, 구분자, Content-Length 등의 Framing 방식을 별도로 정의해야 한다.
2.7 흐름 제어와 혼잡 제어
TCP는 데이터를 정확하게 전달하는 것뿐 아니라 얼마나 많이 전송할 것인지도 조절한다.
흐름 제어(Flow Control)
송신자가 수신자보다 너무 빠르게 데이터를 보내면 수신자의 버퍼가 가득 찰 수 있다.
그래서 TCP는 수신자가 알려주는 **Receive Window(rwnd)**를 이용해 수신자가 감당할 수 있는 만큼 전송한다.
즉 흐름 제어의 목적은 수신자를 보호하는 것이다.
혼잡 제어(Congestion Control)
수신자는 충분히 빠르더라도 데이터가 지나가는 네트워크 자체가 혼잡할 수 있다.
TCP는 Congestion Window(cwnd) 등을 이용해 네트워크 상황에 따라 전송량을 조절한다.
즉 혼잡 제어의 목적은 네트워크 과부하를 방지하는 것이다.
| 구분 | 흐름 제어 | 혼잡 제어 |
|---|---|---|
| 목적 | 수신자 보호 | 네트워크 보호 |
| 기준 | 수신 처리 능력 | 네트워크 혼잡 |
| 주요 값 | rwnd | cwnd |
3. UDP란?
**UDP(User Datagram Protocol)**는 TCP와 달리 연결 상태를 미리 만들지 않고 데이터를 전송하는 비연결형(Connectionless) 프로토콜이다.
하지만 비연결형이라고 해서 상대방의 주소를 모른다는 뜻은 아니다.
UDP도 데이터를 보내려면 목적지의 IP와 Port가 필요하다.
차이는 TCP처럼 먼저 3-way Handshake를 수행해,
"현재 두 Endpoint가 하나의 연결을 통해 통신하고 있다."
라는 연결 상태를 만들고 지속적으로 관리하지 않는다는 것이다.
TCP
연결 설정
↓
데이터 송수신
↓
연결 상태 유지
↓
연결 종료
UDP
목적지 지정
↓
Datagram 전송
UDP의 주요 특징은 다음과 같다.
- 비연결형(Connectionless)
- 별도의 Handshake 없음
- 데이터 도착 보장 없음
- 순서 보장 없음
- TCP와 같은 자동 재전송 없음
- TCP식 흐름/혼잡 제어 없음
- 기본 헤더 8Byte
- Datagram 단위 전송
3.1 UDP의 Datagram
UDP는 데이터를 Datagram이라는 독립된 메시지 단위로 처리한다.
예를 들어
send("HELLO")
send("WORLD")
라고 두 번 전송했다면 UDP에서는
Datagram 1 → HELLO
Datagram 2 → WORLD
라는 두 개의 독립된 데이터그램으로 처리된다.
한마디로 UDP는 메시지의 경계를 유지한다.
TCP와 비교하면 다음과 같다.
TCP
→ 연속된 바이트의 흐름
→ 메시지 경계 보장 X
UDP
→ 독립된 Datagram
→ 메시지 경계 유지
3.2 UDP는 데이터가 유실되면?
UDP 자체는 손실된 데이터를 TCP처럼 다시 보내주지 않는다.
송신
1 2 3 4 5
3 유실
수신
1 2 4 5
또한
1 3 2 5 4
처럼 순서가 달라질 수도 있다.
UDP는 기본적으로 Best-Effort, 즉 전달을 시도하지만 도착이나 순서를 보장하지 않는 방식으로 동작한다.
TCP와 UDP 모두 Checksum을 이용해 데이터 오류를 검출할 수 있지만, UDP는 TCP처럼 손실 데이터를 자동 재전송하는 기능을 자체적으로 제공하지 않는다.
3.3 그렇다면 UDP는 왜 사용할까?
UDP는 TCP의 연결 설정이나 ACK 기반 신뢰성 제어 등의 기능을 자체적으로 제공하지 않는 대신 구조가 단순하고 오버헤드가 작다.
따라서 일부 데이터 손실보다 낮은 지연이나 최신성이 중요한 상황에서 유용할 수 있다.
대표적으로 다음과 같은 곳에서 사용된다.
-
DNS
-
실시간 음성·영상 통신
-
온라인 게임의 실시간 위치 정보
-
RTP
-
QUIC
게임의 위치 데이터를 다시 생각해보자.
x=100
x=110 ← 유실
x=120
이미 x=120이라는 최신 값이 도착했다면 과거 값인 x=110을 기다리는 것이 오히려 불필요할 수 있다.
그래서 실제 서비스에서도 데이터의 성격에 따라 프로토콜을 다르게 선택할 수 있다.
실시간 위치 정보 → UDP 사용 가능
인증 / 결제 / 채팅
→ TCP 사용 가능
3.4 UDP에서도 신뢰성을 구현할 수 있을까?
가능하다.
정확히는
UDP에서는 신뢰성 있는 통신이 불가능하다.
가 아니라
UDP 프로토콜 자체가 TCP와 같은 신뢰성 기능을 제공하지 않는다.
가 맞다.
필요하다면 UDP 위의 애플리케이션이나 다른 프로토콜에서
Sequence Number
ACK
재전송
순서 재조립
등을 구현할 수 있다.
대표적인 예가 QUIC이다.
HTTP/1.1 → TCP
HTTP/2 → TCP
HTTP/3
↓
QUIC
↓
UDP
QUIC은 UDP 위에서 동작하지만 신뢰성, 손실 복구, 흐름 제어, 혼잡 제어 등의 기능을 제공한다.
4. TCP와 UDP의 차이
지금까지의 내용을 정리하면 다음과 같다.
| 구분 | TCP | UDP |
|---|---|---|
| 연결 방식 | 연결 지향 | 비연결형 |
| 연결 설정 | 3-way Handshake | 없음 |
| 연결 종료 | 일반적으로 4-way Handshake | 없음 |
| 신뢰성 | 제공 | 자체적으로 제공하지 않음 |
| 순서 보장 | O | X |
| 재전송 | O | X |
| 흐름 제어 | O | X |
| 혼잡 제어 | O | X |
| 데이터 형태 | Byte Stream | Datagram |
| 메시지 경계 | 보장 X | 유지 |
| 기본 헤더 | 20Byte | 8Byte |
| 대표 사용 | 웹, 파일 전송 등 | DNS, 게임, 실시간 통신 등 |
따라서 단순히
TCP = 느리지만 안전
UDP = 빠르지만 불안정
이라고 외우는 것은 정확하지 않다.
조금 더 정확하게 이해하면 다음과 같다.
TCP
→ 연결 상태를 관리하고
ACK, 재전송, 순서 제어,
흐름/혼잡 제어 등을 제공한다.
UDP
→ 이러한 기능을 최소화하고
Datagram을 단순하게 전송한다.
결국 어떤 프로토콜을 사용할지는 어떤 데이터 특성이 더 중요한지에 따라 결정한다.
정확성
순서
데이터 유실 방지
↓
TCP
낮은 지연
최신성이 중요
일부 손실 허용 가능
↓
UDP