TCP와 UDP — 데이터가 중간에 사라지면?
서버가 데이터를 A, B, C 순서로 보냈는데 중간에서 B만 사라졌다고 해보겠습니다. C는 먼저 도착했지만 B는 아직 오지 않았습니다. 받는 쪽에서는 A와 C를 바로 읽게 될까요, 아니면 B가 도착할 때까지 기다려야 할까요?
앞선 URL·DNS·IP 글에서 목적지를 찾았다면, 이번에는 그 컴퓨터와 데이터를 어떻게 주고받는지 살펴볼 차례입니다. 이후 HTTP 통신 구조로 이어지는 연결도 함께 볼 수 있습니다.
1. TCP와 UDP는 어디에서 동작할까요?
웹 요청이 서버로 전달되려면 여러 계층을 거칩니다. HTTP가 요청과 응답의 내용을 정한다면, IP는 데이터를 목적지 컴퓨터 쪽으로 보냅니다. TCP와 UDP는 그 사이에서 프로그램끼리 데이터를 주고받는 방법을 정합니다. TCP와 UDP 경로를 바꿔 보세요. 각 노드를 누르면 그 단계에서 맡는 일을 확인할 수 있습니다. TCP와 UDP 경로를 비교하는 그림입니다.HTTP 요청은 어떤 길을 지나갈까?
주소를 구분하는 방법도 두 가지가 있습니다. IP 주소가 목적지 컴퓨터를 가리킨다면 는 그 안에서 통신할 프로그램을 구분합니다. 예를 들어 localhost:3000에서 3000이 Port 번호입니다.
프로그램은 이라는 운영체제의 통신 인터페이스를 통해 데이터를 주고받습니다. 서버가 하나의 Port에서 여러 클라이언트 연결을 받을 수 있는 것도 각 연결을 출발지와 목적지의 IP·Port 조합 등으로 구분하기 때문입니다.
2. TCP와 UDP는 무엇이 다를까요?
**TCP(Transmission Control Protocol)**는 연결을 먼저 맺고, 빠진 데이터가 있으면 다시 보내며 바이트를 순서대로 전달합니다. **UDP(User Datagram Protocol)**는 개별 데이터그램을 보내는 데 집중하고, 유실 복구와 순서 정리는 기본적으로 제공하지 않습니다.
| 구분 | TCP | UDP |
|---|---|---|
| 시작 | 연결을 먼저 맺음 | TCP식 연결 수립 과정 없음 |
| 전달 형태 | 순서 있는 바이트 스트림 | 개별 데이터그램 |
| 유실·순서 변경 | 확인 응답과 재전송으로 복구 시도 | 자체 복구·순서 보장 없음 |
| 전송량 조절 | 흐름 제어·혼잡 제어 제공 | UDP 자체에서는 제공하지 않음 |
파일 다운로드에서는 데이터가 빠지면 파일이 제대로 완성되지 않으므로 복구가 중요합니다. 반대로 실시간 음성 통화에서는 이미 지나간 소리를 늦게 받아도 의미가 적을 수 있어, 일부 통신은 UDP를 바탕으로 지연과 손실을 직접 처리합니다. UDP가 항상 더 빠르다는 뜻은 아니고, 필요한 보장이 다른 셈입니다.
또 하나 기억할 점은 TCP가 메시지 경계를 보존하지 않는다는 것입니다. A, B, C를 따로 write()했어도 받는 쪽에서 ABC를 한 번에 읽을 수 있습니다. TCP는 바이트 순서를 지키고, UDP는 개별 데이터그램의 경계를 유지합니다. UDP 헤더에는 출발지·목적지 Port, 길이, 오류 검사용 체크섬 등이 있지만 TCP처럼 SYN·ACK 플래그나 순서 번호는 없습니다.
3. TCP는 왜 세 번 확인하고 연결할까요?
TCP가 네트워크로 보내는 단위는 입니다. 앞쪽 **헤더(Header)**에는 출발지·목적지 Port, 순서 번호(SEQ), 확인 번호(ACK), 제어 플래그(Flags), 수신 윈도 같은 정보가 들어갑니다. 실제로 전달할 데이터는 그 뒤에 붙습니다. 3-way Handshake는 주로 이 헤더의 정보를 주고받는 과정입니다.
여기서 SYN, ACK, FIN, RST는 각각 다른 프로토콜이 아니라, TCP 헤더에 붙는 제어 플래그입니다. 편지에 붙이는 '시작', '확인', '종료' 표시처럼 생각하면 됩니다.
| TCP 플래그 | 의미 | 주로 언제 보이나요? |
|---|---|---|
| Synchronize. 시작 순서 번호를 맞추겠다는 표시 | 연결 시작 | |
| Acknowledgment. 확인 번호가 유효하다는 표시 | 연결 수립의 응답, 데이터 확인 | |
| Finish. 이 방향에서 보낼 데이터가 끝났다는 표시 | 정상 종료 | |
| Reset. 연결을 강제로 중단하겠다는 표시 | 연결 거부·오류 등 |
TCP 연결을 시작할 때는 SYN → SYN+ACK → ACK 순서로 오갑니다. 가운데 SYN → SYN+ACK → ACK 순서로 시작 번호를 맞춥니다. 응답 번호를 예상한 뒤 단계를 넘겨 보세요. 클라이언트가 서버가 지정된 Port에서 연결 요청을 기다리고 있습니다. 아직 연결을 맺기 전입니다. 이 그림의 SYN·ACK는 TCP 헤더 플래그이고, ACK=101·ACK=501은 실제 확인 번호입니다. HTTPS용 TLS 절차는 바로 아래에서 이어집니다.SYN+ACK는 플래그 두 개를 동시에 켠 세그먼트입니다. 클라이언트와 서버가 서로의 초기 순서 번호를 확인하는 과정을 3-way Handshake라고 합니다.3-way Handshake — 세 번 주고받는 이유
SYN, SEQ=100을 보냈다면 서버는 어떤 ACK 번호로 응답할까요?
이때 는 Sequence Number, 즉 바이트의 위치를 나타내는 번호입니다. 클라이언트가 SYN, SEQ=100을 보냈다면 서버는 ACK=101로 답합니다. SYN 자체가 순서 번호 한 칸을 차지하기 때문입니다. 서버도 자기 시작 번호를 보내고, 클라이언트가 이를 확인하면 연결이 수립됩니다.
여기서 ACK 플래그와 ACK 번호는 다릅니다. ACK 플래그는 '확인 번호를 사용한다'는 표시이고, ACK=101은 '다음에 101번부터 받겠다'는 실제 숫자입니다. 연결을 마친 상태는 ESTABLISHED라고 부릅니다. 3-way Handshake는 서로 시작 번호를 맞추고 연결 상태를 만드는 과정이지 암호화 과정은 아닙니다.
4. 그럼 HTTPS는 언제 암호화될까요?
TCP는 데이터 순서를 맞춰주지만 내용을 암호화하지는 않습니다. HTTPS에서는 TCP 연결을 맺은 다음 로 서버의 신원을 확인하고 암호화에 필요한 키를 합의합니다. 전송이 제대로 되는 것과 다른 사람이 내용을 읽을 수 없게 하는 것은 별개의 문제입니다.
예를 들어 인증서가 정상일 때와 도메인 이름이 다를 때를 비교하면서 TLS 연결 흐름을 살펴보세요. 브라우저가 사용할 수 있는 TLS 버전·암호 방식과 키 교환 정보를 보냅니다. 실제 사이트에 접속하거나 암호화를 수행하는 기능은 아닙니다. TLS 1.3의 주요 흐름을 단순화한 학습용 그림입니다. HTTP/3의 QUIC에서는 TLS 1.3 절차가 QUIC 연결 안에 포함됩니다.https://shop.example.com에 접속하면 서버는 를 제시합니다. 브라우저는 인증서에 해당 도메인이 적혀 있는지, 유효기간이 지났는지, 신뢰할 수 있는 (인증기관)를 통해 확인되는지 검사합니다. 인증서만 받았다고 끝나는 게 아니라 서버가 그 인증서와 연결된 개인키를 실제로 갖고 있는지도 확인합니다.연결된 서버가 진짜인지 어떻게 확인할까요?
TLS 1.3에서는 브라우저의 ClientHello, 서버의 ServerHello, 서버 인증과 키 합의, 양쪽의 Finished 확인을 거쳐 암호화된 HTTP 데이터를 주고받습니다. 인증서가 맞지 않으면 브라우저가 경고하고 연결을 막을 수 있습니다. 여기서는 복잡한 암호 수학보다 상대가 맞는지 확인하고, 암호화할 키를 함께 정한다는 목적을 이해하면 됩니다.
HTTP/3는 방식이 조금 다릅니다. TCP를 거치지 않고 UDP 기반 에서 TLS 1.3 핸드셰이크를 연결 과정에 통합해 사용합니다. 그래서 'HTTPS는 언제나 TCP 연결 뒤에 TLS를 한다'고 외우면 HTTP/3에는 맞지 않습니다.
5. B가 사라졌는데 C가 먼저 도착했다면?
TCP는 각 바이트에 번호를 붙여 어디까지 받았는지 추적합니다. A가 10001099번, B가 11001199번, C가 1200~1299번 바이트라고 해보겠습니다. A를 받은 수신자가 ACK=1100으로 응답하는 건 1099번까지 받았고 다음에는 1100번부터 필요하다는 의미입니다.
이 덕분에 송신자는 어떤 부분이 아직 확인되지 않았는지 알 수 있습니다. B가 유실된 채 C가 먼저 도착했다면 TCP는 C를 버퍼에 보관할 수 있지만, 앱에는 B를 건너뛰고 C부터 내주지 않습니다.
아래 그림에서 B를 유실시키거나 도착 순서를 바꿔 보면 차이가 더 분명해집니다. TCP와 UDP를 번갈아 선택하면서 앱이 실제로 읽을 수 있는 데이터를 비교해 보세요. B를 유실시키거나 C가 먼저 도착하도록 바꿔 보세요. 앱에서 읽을 수 있는 데이터가 어떻게 달라지는지 확인할 수 있습니다. 결과를 예상한 뒤 실험을 시작하면 단계별로 데이터가 어떻게 바뀌는지 볼 수 있습니다. A·B·C는 각각 100바이트로 가정한 예시입니다. 실제 패킷을 전송하지는 않고, TCP의 바이트 순서와 누적 ACK를 단순하게 보여줍니다.B가 빠졌을 때 TCP와 UDP는 어떻게 다를까?
TCP는 예상한 시간 안에 ACK가 돌아오지 않거나 중복 ACK 같은 신호를 받으면 손실을 의심하고 B를 다시 보낼 수 있습니다. 왕복 시간인 등을 참고해 재전송 타이머를 조절합니다. B가 도착하면 보관해 둔 C까지 이어져 앱은 ABC를 순서대로 읽습니다. 여기서 **버퍼(Buffer)**는 먼저 도착한 데이터를 잠시 담아두는 메모리 공간입니다.
UDP에서는 같은 상황에 B를 자동으로 다시 보내는 과정이 없습니다. 그래서 A와 C만 도착할 수도 있고, C가 A보다 먼저 도착할 수도 있습니다. 이런 경우의 복구와 정렬은 필요에 따라 애플리케이션이나 상위 프로토콜에서 처리해야 합니다.
HTTP/3는 UDP를 쓰는데 괜찮을까요?
HTTP/3는 UDP를 그대로 이용하는 게 아니라 그 위에 QUIC이라는 프로토콜을 사용합니다. QUIC이 손실 복구와 연결 관리 등을 구현하기 때문에 HTTP/3도 신뢰성 있는 통신이 가능합니다. 반면 HTTP/1.1과 HTTP/2는 TCP를 사용합니다.
TCP는 B가 빠지면 뒤쪽 C가 이미 도착해도 앱에서 기다려야 합니다. 이런 현상을 Head-of-line Blocking이라고 합니다. HTTP/2의 여러 스트림은 같은 TCP 연결의 유실 영향을 받을 수 있지만, QUIC은 스트림을 독립적으로 관리해 이 문제를 줄입니다.
6. 데이터를 많이 보내면 더 빠를까요?
TCP는 데이터를 무조건 많이 보내지 않습니다. 받는 프로그램이 처리할 수 있는 양과 네트워크가 감당할 수 있는 양을 함께 고려합니다. 둘 다 전송량을 제한하지만 막히는 위치가 다릅니다.
받는 쪽이 느려 수신 버퍼가 차는 문제는 **흐름 제어(Flow Control)**로 다룹니다. 수신자가 지금 받을 수 있는 공간을 알리는 값이 (receive window)입니다. 반면 네트워크에 패킷이 몰리는 문제는 **혼잡 제어(Congestion Control)**로 다루며, 송신 측의 제한을 (congestion window)라고 부릅니다. 받는 쪽이 느릴 때와 네트워크가 혼잡할 때를 각각 조절해 보세요. rwnd와 cwnd의 차이를 확인할 수 있습니다. 수신자가 병목입니다. 받는 쪽에서 데이터를 읽어 버퍼를 비워야 합니다. 실제 TCP는 이미 전송하고 ACK를 기다리는 데이터도 고려합니다. 이 실습에서는 두 윈도의 역할을 비교합니다.받는 사람이 느린가, 네트워크가 막혔는가?
rwnd를 줄이면 수신자 버퍼가 병목이 되고, cwnd를 줄이면 네트워크 혼잡에 따른 제한이 더 크게 작용합니다. 실제 TCP는 이미 보내고 ACK를 기다리는 데이터도 함께 고려하지만, 여기서는 두 값이 맡는 역할을 비교해 보면 됩니다.
7. 연결을 끊을 때도 확인이 필요할까요?
TCP는 양방향으로 데이터를 보낼 수 있습니다. 클라이언트가 보낼 일을 마쳤어도 서버가 아직 응답을 보내는 중일 수 있어서, 한쪽의 전송 종료와 다른 쪽의 종료를 따로 확인합니다. 일반적인 흐름은 FIN → ACK → FIN → ACK입니다. 은 더 보낼 데이터가 없다는 뜻이고, 는 정상 종료를 기다리지 않고 연결을 중단할 때 쓰는 신호입니다. 클라이언트가 보낼 데이터를 모두 보낸 뒤에도 서버는 데이터를 더 보낼 수 있습니다. 양쪽의 종료 과정을 단계별로 살펴보세요. 양쪽이 데이터를 보내고 받을 수 있는 상태입니다. FIN → ACK → FIN → ACK의 일반적인 종료 흐름입니다. 실제로는 종료 상황에 따라 다른 순서도 가능합니다.TCP 연결은 어떻게 끝날까?
먼저 연결 종료를 시작한 쪽은 마지막 ACK를 보낸 뒤에도 상태로 잠시 남을 수 있습니다. 늦게 도착한 세그먼트를 처리하거나 마지막 ACK를 다시 보내야 할 상황에 대비하기 위해서입니다. 실제로는 양쪽이 동시에 종료하거나 RST로 끝나는 경우도 있습니다.
8. 브라우저에서는 어떻게 확인할까요?
Chrome DevTools의 Network 탭 → Protocol 열을 보면 요청이 어떤 HTTP 버전으로 처리됐는지 확인할 수 있습니다. h2는 TCP 위의 HTTP/2, h3는 UDP 기반 QUIC을 사용하는 HTTP/3입니다. 평소 사용하는 웹 요청도 이런 전송 방식 위에서 동작합니다.
그렇다고 fetch()를 한 번 호출할 때마다 TCP 연결을 새로 만드는 건 아닙니다. 브라우저는 연결을 재사용할 수 있고, HTTP/2에서는 여러 요청을 한 연결로 처리할 수도 있습니다. 요청이 느린 이유도 TCP 손실 때문이라고 바로 단정하기보다 서버 처리와 네트워크 상황을 함께 봐야 합니다.
정리
처음의 A·B·C 상황으로 돌아가면 차이가 분명합니다. TCP는 순서 번호와 ACK로 누락된 부분을 추적하고 재전송으로 복구를 시도합니다. UDP는 이 기능을 기본으로 제공하지 않으며, 필요하면 그 위의 프로토콜이 맡습니다.
TCP의 전체 흐름은 연결 수립 → 데이터 확인·재전송 → 전송량 조절 → 연결 종료로 이어집니다. HTTPS에서는 여기에 서버 인증과 암호화를 담당하는 TLS가 더해집니다. 각 단계에서 어떤 문제를 해결하는지 이해하면 TCP와 UDP를 단순히 '안전하다', '빠르다'로 구분하지 않아도 됩니다.
복습 문제
그림 없이도 설명할 수 있을까?
답을 고른 뒤, 그 이유도 직접 설명해 보세요.