TCP, UDP, TLS
브라우저 주소창에 https://asap-note.pages.dev 를 입력하면 화면이 뜨기까지 TCP, UDP, TLS 가 차례로 쓰입니다.
세 가지는 서로 다른 문제를 풉니다. 데이터가 빠짐없이 도착하는지, 얼마나 빨리 도착하는지, 중간에서 누가 볼 수 없는지입니다.
이 글은 각각이 무엇을 해결하는지 그림과 코드로 확인하고, 마지막에 한 번의 HTTPS 요청에서 세 가지가 어떻게 이어지는지 봅니다.
1. 통신하려면 무엇이 필요할까
브라우저(클라이언트)가 요청을 보내면 서버가 응답합니다. 요청과 응답 데이터는 한 번에 전송되지 않고 여러 조각으로 나뉘어 이동합니다.
패킷은 전송을 위해 나눈 데이터 조각 하나입니다. 목적지 주소 같은 제어 정보를 담은 헤더와 실제 데이터로 이루어집니다. TCP 에서는 세그먼트, UDP 에서는 데이터그램이라고도 부르지만 이 글에서는 패킷으로 통일합니다.
패킷이 어디로 가야 하는지, 도중에 사라지면 어떻게 하는지, 중간에서 읽히면 어떻게 하는지를 미리 정해 두어야 통신이 됩니다.
1.1 IP, 포트, 프로토콜
- IP 주소: 네트워크에서 컴퓨터 한 대를 식별하는 번호입니다. 예:
198.51.100.7 - 포트: 한 컴퓨터 안에서 통신하는 프로그램을 식별하는 0~65535 사이의 번호입니다.
- 프로토콜: 주고받는 데이터의 형식과 순서를 정한 규칙입니다. HTTP, TCP, UDP, TLS 가 모두 프로토콜입니다.
연결의 목적지는 IP 주소와 포트 번호 한 쌍으로 정해집니다.
서버는 같은 IP 주소에서 포트 번호로 서비스를 나눕니다. 웹은 관례적으로 HTTP 가 80, HTTPS 가 443 입니다. 클라이언트의 포트는 OS 가 연결마다 임시로 배정합니다. 같은 PC 에서 같은 서버로 연결을 여러 개 열어도 포트 번호로 구분됩니다.
1.2 TCP, UDP, TLS 의 역할
| 정의 | 위치 | |
|---|---|---|
| TCP | 연결을 만든 뒤, 데이터의 도착 여부와 순서를 확인하며 전송하는 프로토콜 | 전송 계층 |
| UDP | 연결과 확인 절차 없이 데이터를 전송하는 프로토콜 | 전송 계층 |
| TLS | 전송하는 데이터를 암호화하고 서버의 신원을 확인하는 프로토콜 | TCP 위, HTTP 아래 |
전송 계층은 IP 가 컴퓨터까지 전달한 패킷을 포트 번호로 프로그램에 넘기는 계층입니다. TCP 와 UDP 는 이 계층에서 둘 중 하나를 고르는 관계입니다. TLS 는 TCP 나 UDP 를 대체하지 않고 그 위에서 암호화와 인증을 추가합니다. 웹은 TCP 위에 TLS 를 얹어 씁니다.
2. TCP: 전달을 어떻게 보장할까
TCP(Transmission Control Protocol)는 데이터를 보내기 전에 연결을 만들고, 보낸 데이터마다 수신 확인을 받는 프로토콜입니다. 이 방식으로 데이터의 도착 여부와 순서를 보장합니다.
2.1 연결 시작과 종료
TCP 헤더의 플래그 세 가지를 먼저 정의합니다.
- SYN: 연결을 요청하는 플래그입니다.
- ACK: 데이터나 요청을 받았다는 확인 플래그입니다.
- FIN: 연결을 종료하겠다는 플래그입니다.
연결을 만드는 3-Way Handshake 는 세 단계입니다.
- SYN: 클라이언트가 자기 시작 번호(seq)를 담아 연결을 요청합니다.
- SYN+ACK: 서버가 요청을 확인하고(
ack=101은 100번까지 받았으니 다음은 101번이라는 뜻) 자기 시작 번호를 보냅니다. - ACK: 클라이언트가 서버의 시작 번호를 확인합니다. 이때부터 데이터를 보냅니다.
양쪽이 각자 시작 번호를 알리고 상대가 받았음을 확인해야 하므로 세 번이 필요합니다. 시작 번호는 연결마다 무작위로 정해집니다.
연결을 끝내는 4-Way Handshake 는 닫는 방향이 둘이라 네 번입니다. 클라이언트가 FIN 을 보내도 서버는 아직 보낼 데이터가 남았을 수 있습니다. 그럼 ACK 만 먼저 돌려주고, 다 보낸 뒤에 자기 FIN 을 보냅니다.
클라이언트는 마지막 ACK 가 유실되어 서버가 FIN 을 다시 보내는 경우에 대비해 TIME_WAIT 상태로 잠시 머뭅니다.
2.2 번호, ACK, 재전송
- 번호: 보내는 데이터에 순서대로 번호(seq)를 붙입니다.
- ACK: 받는 쪽이
ack=N으로 N번 전까지 받았고 다음은 N번이라고 알립니다. - 재전송: ACK 가 제한 시간 안에 오지 않거나 같은 ack 가 여러 번 반복되면 보내는 쪽이 그 구간을 다시 보냅니다.
- 순서 보장: 데이터가 뒤섞여 도착해도 받는 쪽이 번호로 이어 붙인 뒤 애플리케이션에 순서대로 넘깁니다.
이 밖에 받는 쪽이 처리할 수 있는 양에 맞추는 흐름 제어, 네트워크가 막히면 속도를 낮추는 혼잡 제어도 TCP 가 맡습니다. 신뢰성의 대가로 시작할 때 왕복이 필요하고, 패킷 하나가 유실되면 뒤에 도착한 데이터도 빈 구간이 채워질 때까지 기다립니다.
3. UDP: 무엇을 생략해서 빠를까
UDP(User Datagram Protocol)는 연결을 만들지 않고 데이터를 포트로 전달하기만 하는 프로토콜입니다. 수신 확인, 재전송, 순서 맞추기를 하지 않습니다. 헤더도 8바이트로 TCP(최소 20바이트)보다 작습니다.
3.1 TCP 와 UDP 의 차이
아무도 듣지 않는 포트로 보내면 두 프로토콜의 차이가 바로 드러납니다.
import dgram from 'node:dgram';
import net from 'node:net';
const udp = dgram.createSocket('udp4');
udp.send('hello', 41234, '127.0.0.1', (err) => {
console.log('UDP:', err ? err.message : '전송 성공');
udp.close();
});
net.connect(41234, '127.0.0.1').on('error', (e) => console.log('TCP:', e.code));
UDP: 전송 성공
TCP: ECONNREFUSED
UDP 의 전송 성공은 내보냈다는 뜻일 뿐 도착했다는 뜻이 아닙니다. TCP 는 연결 단계에서 상대에게 거절당해 바로 실패합니다.
| TCP | UDP | |
|---|---|---|
| 연결 | 만든 뒤 전송 | 없이 바로 전송 |
| 전달 확인 | ACK 와 재전송 | 없음 |
| 순서 | 번호로 보장 | 보장 안 함 |
UDP 가 빠른 이유는 전송 속도 자체가 아니라 기다림이 없기 때문입니다.
3.2 언제 무엇을 쓸까
데이터가 하나라도 빠지면 쓸 수 없으면 TCP 를 쓰고, 늦게 도착한 데이터가 쓸모없으면 UDP 를 씁니다.
| 프로토콜 | 사용 예 | 선택 이유 |
|---|---|---|
| TCP | 웹 페이지, API 요청(HTTP/1.1, HTTP/2) | HTML 이나 JSON 은 일부만 받으면 해석할 수 없음 |
| TCP | WebSocket 채팅 | HTTP 로 시작한 연결을 유지하며 메시지를 순서대로 주고받음 |
| TCP | SSH, 이메일(SMTP), 파일 전송 | 명령, 메일, 파일 내용이 빠지거나 순서가 바뀌면 안 됨 |
| UDP | DNS 질의 | 요청 하나와 응답 하나로 끝나서 연결을 만드는 단계가 오히려 부담 |
| UDP | 실시간 음성·영상 통화 | 재전송된 패킷은 도착했을 때 이미 재생 시점이 지났음 |
| UDP | 온라인 게임의 위치 갱신 | 최신 값이 계속 오므로 유실된 이전 값을 다시 받을 필요가 없음 |
4. TLS: 안전하게 보내려면
4.1 TLS 란
TLS(Transport Layer Security)는 TCP 연결 위에서 데이터를 암호화하고 서버의 신원을 확인하는 프로토콜입니다.
TCP 는 데이터의 도착은 보장하지만 내용을 암호화하지 않습니다. 경로 중간에서 패킷을 읽을 수 있으면 로그인 정보가 그대로 보입니다.
HTTP : POST /login HTTP/1.1 ... password=1234
HTTPS: 17 03 03 00 5a 8f 2c e1 b4 07 ... (암호문)
TLS 가 제공하는 세 가지 기능입니다.
| 기능 | 정의 | 막는 위협 |
|---|---|---|
| 암호화(기밀성) | 세션 키로 데이터를 암호문으로 바꿔 전송 | 중간에서 내용을 읽는 것 |
| 무결성 | 데이터마다 검증 값을 붙여 전송 중 변조를 감지 | 중간에서 내용을 바꾸는 것 |
| 인증 | 서버가 보낸 인증서로 접속한 서버의 신원을 확인 | 가짜 서버에 접속하는 것 |
4.2 TLS Handshake 와 인증서
세션 키는 이 연결의 데이터를 암호화하는 데 쓰는 키입니다.
- Hello 교환: 사용할 암호 방식을 정하고 서로 키 재료(공개 값)를 보냅니다. 양쪽이 같은 세션 키를 계산하며 세션 키 자체는 네트워크로 전송되지 않습니다.
- 인증서 전달: 서버가 인증서와 서명을 보냅니다. 서명은 인증서의 공개 키와 짝인 비밀 키로 만들며, 이 서버가 그 비밀 키를 가졌다는 증거입니다.
- Finished: 지금까지 주고받은 Handshake 메시지가 양쪽에서 같았는지 확인합니다.
- 데이터 전송: 이후 모든 데이터를 세션 키로 암호화합니다.
키를 합의하는 데는 느린 비대칭 방식을 쓰고, 대량의 데이터는 빠른 대칭 방식으로 암호화합니다. TLS 1.3 은 이 과정이 왕복 1번이고 TLS 1.2 는 2번입니다.
인증서는 서버의 공개 키, 도메인 이름, 만료일, 발급한 CA 의 서명을 담은 문서입니다. CA(인증 기관)는 도메인 소유자를 확인하고 인증서에 서명하는 기관입니다. 브라우저는 OS 와 브라우저에 미리 들어 있는 신뢰 CA 목록으로 세 가지를 확인합니다. 서명이 신뢰하는 CA 로 이어지는지, 접속한 도메인과 일치하는지, 만료되지 않았는지입니다. 하나라도 어긋나면 경고 화면이 뜹니다.
curl -v 로 같은 과정을 볼 수 있습니다.
* (304) (OUT), TLS handshake, Client hello (1):
* (304) (IN), TLS handshake, Server hello (2):
* (304) (IN), TLS handshake, Certificate (11):
* (304) (IN), TLS handshake, CERT verify (15):
* (304) (IN), TLS handshake, Finished (20):
* (304) (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / AEAD-CHACHA20-POLY1305-SHA256
* subject: CN=asap-note.pages.dev
* issuer: C=US; O=Google Trust Services; CN=WE1
* SSL certificate verify ok.
4.3 HTTP 와 HTTPS 의 차이
HTTPS 는 별개의 프로토콜이 아니라 HTTP 를 TLS 위에서 보내는 방식입니다. 요청 메시지의 모양은 그대로입니다.
| HTTP | HTTPS | |
|---|---|---|
| 기본 포트 | 80 | 443 |
| 전송 구간 | 평문 | TLS 로 암호화 |
| 서버 신원 | 확인하지 않음 | 인증서로 확인 |
| 준비물 | 없음 | CA 에서 발급한 인증서 |
| HTTP/2, HTTP/3 | 브라우저에서 사용 불가 | 사용 가능 |
4.4 TLS 와 SSH
둘 다 TCP 위에서 키를 합의하고 대칭 암호로 보호하는 구조는 같습니다. 서버를 믿는 방법과 쓰는 곳이 다릅니다.
| TLS | SSH | |
|---|---|---|
| 주 용도 | 웹, API 등 서비스 통신 보호 | 원격 서버 셸 접속, 파일 전송 |
| 기본 포트 | 443 | 22 |
| 서버를 믿는 방법 | CA 가 서명한 인증서 | 첫 접속 때 호스트 키를 확인하고 known_hosts 에 저장해 이후 비교 |
| 사용자 인증 | 보통 없음(앱이 로그인 처리) | 비밀번호 또는 SSH 키 |
5. 실제 웹 통신 과정
5.1 HTTPS 페이지에 접속하면
- DNS 조회: 도메인을 IP 주소로 바꿉니다. 짧은 질의와 응답이라 보통 UDP 를 씁니다.
- TCP 연결: 그 IP 의 443 포트로 3-Way Handshake 를 합니다.
- TLS Handshake: 인증서를 검증하고 세션 키를 만듭니다.
- HTTP 요청·응답: 암호화된 연결 위에서 요청을 보내고 응답을 받습니다.
curl 로 단계마다 걸린 시간을 확인할 수 있습니다.
curl -so /dev/null -w 'dns %{time_namelookup}\nconnect %{time_connect}\ntls %{time_appconnect}\nfirstbyte %{time_starttransfer}\n' https://asap-note.pages.dev
dns 0.019481
connect 0.024840
tls 0.037465
firstbyte 0.160090
각 값은 요청을 시작한 시점부터의 누적 시간입니다. 단계별 비용은 앞 값과의 차이입니다. TCP 는 0.024840 - 0.019481 = 약 5.4ms, TLS 는 0.037465 - 0.024840 = 약 12.6ms 입니다.
이 비용은 처음 연결할 때만 붙습니다. 같은 연결을 재사용하는 이후 요청은 4단계만 거칩니다. 서버가 멀수록 왕복 한 번이 길어지므로, 첫 바이트를 받기까지 지나는 왕복 3번(TCP, TLS, HTTP 요청)이 체감 시간이 됩니다.
5.2 한눈에 비교
| TCP | UDP | TLS | |
|---|---|---|---|
| 해결하는 문제 | 전달 여부와 순서 | 기다림 없는 전달 | 도청, 변조, 사칭 |
| 시작할 때 | 3-Way Handshake | 없음 | TLS Handshake (TCP 연결 위에서) |
| 유실이 나면 | 재전송 | 그대로 둠 | 하위 프로토콜에 따름 |
| 내용 보호 | 없음 | 없음 | 암호화, 무결성, 인증 |