TCP와 UDP는 transport layer protocol입니다. TCP는 연결을 맺고 데이터를 순서대로, 손실되면 재전송하면서 전달하려고 합니다. 그래서 웹, 파일 전송처럼 정확성과 순서가 중요한 곳에 많이 쓰입니다. UDP는 연결 설정이나 재전송, 순서 보장을 기본으로 제공하지 않습니다.
대신 단순하고 빠르며 지연이 작을 수 있어 실시간 음성, 영상, 게임, DNS 같은 곳에서 쓰입니다. 다만 UDP를 쓴다고 항상 신뢰성이 필요 없다는 뜻은 아니고, 필요한 보장은 application layer에서 직접 설계할 수 있습니다.
꼬리질문
조금 더 깊게 물어본다면
답변 뒤에 이어질 수 있는 질문들을 하나씩 열어볼 수 있어요.
TCP 3-way handshake는 왜 3단계인가요?
양쪽이 서로 송수신이 가능하다는 것을 확인하고, 초기 sequence number를 교환하기 위해 3단계가 필요합니다.
SYN: 클라이언트가 자신의 초기 sequence number(ISN)를 담아 연결을 요청합니다.
SYN-ACK: 서버가 클라이언트의 ISN+1을 ACK로 확인하고, 자신의 ISN을 담아 응답합니다.
ACK: 클라이언트가 서버의 ISN+1을 ACK로 확인합니다.
2단계만으로는 서버가 자신의 응답이 클라이언트에게 도달했는지 알 수 없습니다. sequence number 교환을 통해 이후 패킷 순서와 손실 감지의 기준점을 만드는 것이 핵심 목적입니다.
TCP 연결 종료는 왜 4단계인가요?
4-way handshake로 종료됩니다. 연결 설정의 SYN-ACK와 달리 FIN과 ACK를 합칠 수 없기 때문입니다.
FIN: 클라이언트가 더 이상 보낼 데이터가 없음을 알립니다.
ACK: 서버가 FIN을 확인합니다. 이 시점에 서버는 아직 보낼 데이터가 남아 있을 수 있습니다.
FIN: 서버가 모든 데이터를 보낸 뒤 종료를 알립니다.
ACK: 클라이언트가 서버의 FIN을 확인합니다.
서버가 클라이언트의 FIN을 받은 시점에 전송 중인 데이터가 남아 있을 수 있어 FIN을 즉시 보낼 수 없습니다. 그래서 ACK와 FIN이 분리됩니다.
TIME_WAIT 상태는 무엇인가요?
클라이언트가 마지막 ACK를 보낸 뒤 바로 소켓을 닫지 않고 일정 시간(보통 2*MSL, 약 1-4분) 동안 대기하는 상태입니다.
이유는 두 가지입니다. 첫째, 마지막 ACK가 유실되면 서버가 FIN을 재전송하는데 그 FIN을 받아 ACK를 다시 보내야 합니다. 둘째, 이전 연결에서 늦게 도착한 패킷이 같은 포트로 열린 새 연결에 섞이는 것을 막습니다.
TIME_WAIT가 많이 쌓이면 포트가 고갈되어 새 연결을 맺기 어려울 수 있습니다. 고부하 서버에서는 SO_REUSEADDR나 tcp_tw_reuse 옵션으로 대응합니다.
TCP는 패킷 순서와 손실을 어떻게 보장하나요?
각 세그먼트에 sequence number를 붙여 순서를 추적하고, 수신 측이 ACK로 받은 바이트 범위를 확인합니다. 일정 시간 ACK가 오지 않으면 재전송합니다.
수신 측은 버퍼에서 sequence number 순서대로 데이터를 조립해 애플리케이션에 전달합니다. 중간 패킷이 빠지면 그 이후 패킷을 버퍼에 보관하고 빠진 번호의 ACK를 반복해서 보내 재전송을 유도합니다(duplicate ACK).
flow control과 congestion control의 차이는?
flow control은 수신 측이 처리할 수 있는 속도에 맞춰 송신 속도를 조절하는 것입니다. 수신 측이 receive window 크기를 ACK에 담아 보내면 송신 측은 그 크기 이상을 ACK 없이 보내지 않습니다. 수신 버퍼 overflow를 막기 위한 end-to-end 메커니즘입니다.
congestion control은 네트워크 전체의 혼잡을 감지해 송신 속도를 줄이는 것입니다. 패킷 손실을 혼잡 신호로 보고 cwnd(congestion window)를 조절합니다. 처음에 slow start로 천천히 속도를 높이다가 손실이 발생하면 급격히 줄이는 AIMD(Additive Increase Multiplicative Decrease) 방식이 기본입니다.
둘의 차이는 누구를 위한 제어냐입니다. flow control은 수신 측을 위한 것이고, congestion control은 네트워크 전체를 위한 것입니다.
TCP의 head-of-line blocking이란?
TCP는 스트림 순서를 보장하기 때문에 앞 패킷이 손실되면 뒤 패킷이 이미 도착해 있어도 애플리케이션에 전달하지 않고 기다립니다.
HTTP/2는 하나의 TCP 연결에서 여러 스트림을 멀티플렉싱하는데, 패킷 하나가 손실되면 그 TCP 연결의 모든 스트림이 멈춥니다. 다른 스트림의 데이터는 이미 도착해 있어도 애플리케이션은 기다려야 합니다. HTTP/3가 UDP를 선택한 핵심 이유가 이것입니다.
UDP는 신뢰성이 전혀 없나요?
UDP 자체는 전달 보장, 순서 보장, 중복 제거를 제공하지 않습니다. 하지만 애플리케이션이 필요한 신뢰성만 선택적으로 구현할 수 있습니다.
QUIC이 대표적입니다. UDP 위에서 스트림별 순서 보장, 손실 재전송, 암호화를 구현합니다. TCP와 달리 스트림 단위로 재전송하기 때문에 한 스트림의 손실이 다른 스트림을 막지 않습니다.
실시간 영상 통화는 왜 UDP를 선호하나요?
늦게 도착한 패킷보다 최신 패킷이 더 중요하기 때문입니다. TCP처럼 손실 패킷을 재전송받아야 한다면, 그 사이 들어온 정상 패킷은 버퍼에 쌓이고 지연이 계속 늘어납니다. 화상 통화에서 0.5초 전 영상 프레임은 이미 의미가 없습니다.
UDP를 쓰면 손실이 생겨도 건너뜁니다. 잠깐 화질이 떨어지더라도 지연 없이 최신 프레임을 보여줄 수 있습니다. WebRTC가 이 방식을 씁니다.
DNS는 왜 UDP를 주로 쓰나요?
요청과 응답이 단일 패킷에 들어올 만큼 작고, 연결 설정 없이 빠르게 왕복해야 하기 때문입니다. TCP 3-way handshake를 거치면 쿼리 하나에 최소 1.5 RTT가 필요한데, UDP는 1 RTT로 처리됩니다.
응답 크기가 EDNS로 협상한 최대 크기를 초과하거나, zone transfer처럼 대량 데이터를 전송할 때는 TCP를 사용합니다.
HTTP/3는 왜 UDP를 선택했나요?
HTTP/2의 TCP head-of-line blocking을 근본적으로 해결하기 위해서입니다. QUIC은 UDP 위에서 스트림별 독립 전달을 구현해, 한 스트림의 패킷 손실이 다른 스트림을 막지 않습니다.
추가로 QUIC은 TLS 1.3을 내장해 handshake를 1 RTT(첫 연결) 또는 0 RTT(재연결)로 줄이고, IP 주소가 바뀌어도 connection ID로 연결을 유지하는 connection migration을 지원합니다. 모바일 환경에서 Wi-Fi와 셀룰러를 오갈 때 연결이 끊기지 않는 이유입니다.
부가 설명
TCP: 연결 지향, 신뢰성, 순서 보장, 재전송, 상대적으로 큰 오버헤드UDP: 비연결형, 순서/전달 보장 없음, 작은 오버헤드, 낮은 지연 가능
TCP는 데이터가 정확히 도착하는 것이 중요할 때 자연스럽고, UDP는 일부 손실보다 실시간성이 더 중요할 때 고려됩니다.
HTTP/1.1과 HTTP/2는 TCP 위에서 동작합니다. HTTP/3는 UDP 위에 QUIC을 올려 TCP의 일부 한계를 줄이려는 방향입니다. 그래서 TCP/UDP 차이는 현대 웹 성능 질문과도 연결됩니다.
한 줄 정리
TCP는 신뢰성과 순서를 보장하려는 연결형 전송이고, UDP는 가볍고 빠른 비연결형 전송입니다.