UDP: 연결 없이 데이터그램을 빠르게 전달하는 전송 계층 프로토콜
사용자 데이터그램 프로토콜(UDP, User Datagram Protocol)은 연결 수립 없이 독립된 데이터그램(Datagram)을 전송한다. 전달 여부와 순서를 보장하지 않는 대신 헤더와 처리 비용이 작고, 애플리케이션이 재전송 정책과 지연 시간을 직접 제어할 수 있다. 실시간 통신, DNS, 온라인 게임처럼 일부 손실보다 낮은 지연 시간이 중요한 환경
By 송민성
1. 개념
사용자 데이터그램 프로토콜(UDP, User Datagram Protocol)은 인터넷 프로토콜(IP, Internet Protocol) 위에서 동작하는 비연결형(Connectionless) 전송 계층 프로토콜이다.
UDP는 데이터를 연속된 바이트 스트림(Byte Stream)이 아닌 독립된 데이터그램(Datagram) 단위로 전달한다.
송신: ["HELLO"] ["WORLD"]
수신: ["HELLO"] ["WORLD"]데이터그램이 정상적으로 도착했다면 송신자가 나눈 메시지 경계가 유지된다. 단, 각 데이터그램은 다음 상황을 겪을 수 있다.
- 유실되어 도착하지 않는다.
- 여러 번 중복 도착한다.
- 송신 순서와 다른 순서로 도착한다.
- 네트워크 경로의 최대 전송 단위(MTU)를 넘으면 단편화되거나 폐기된다.
- 수신 버퍼가 가득 차면 운영체제가 폐기한다.
UDP 자체는 연결 상태, 재전송, 순서 정렬, 흐름 제어(Flow Control), 혼잡 제어(Congestion Control)를 제공하지 않는다.
2. 왜 사용하는가
전송 제어 프로토콜(TCP, Transmission Control Protocol)은 신뢰성을 제공하지만 연결 수립, 확인 응답, 재전송, 순서 복구가 필요하다. UDP는 이 기능을 생략해 다음 장점을 얻는다.
- 연결 수립 과정 없이 즉시 데이터를 보낼 수 있다.
- 패킷 손실 때문에 뒤의 데이터 전달까지 기다리지 않는다.
- 애플리케이션이 재전송 대상과 시점을 직접 정할 수 있다.
- 브로드캐스트(Broadcast)와 멀티캐스트(Multicast)를 사용할 수 있다.
- UDP 헤더 크기가 8바이트로 작다.
UDP가 항상 TCP보다 빠른 것은 아니다. 네트워크 혼잡, 데이터 크기, 운영체제 버퍼, 애플리케이션 구현에 따라 결과가 달라진다. UDP의 핵심 이점은 높은 속도 자체보다 전송 정책을 애플리케이션이 제어할 수 있다는 점이다.
예를 들어 실시간 음성 통화에서는 늦게 재전송된 과거 음성보다 최신 음성을 바로 재생하는 편이 낫다. 반대로 파일 전송에서는 한 바이트의 손실도 허용하기 어려우므로 신뢰성 계층이 필요하다.
3. 동작 원리
3.1 UDP 헤더
UDP 헤더는 고정된 8바이트이며 네 필드로 구성된다.
0 15 16 31
+------------------+------------------+
| 출발지 포트 | 목적지 포트 |
+------------------+------------------+
| 길이 | 체크섬 |
+------------------+------------------+
| 데이터 |
+-------------------------------------+- 출발지 포트(Source Port): 송신 애플리케이션의 포트 번호
- 목적지 포트(Destination Port): 수신 애플리케이션의 포트 번호
- 길이(Length): 헤더와 데이터를 합친 UDP 데이터그램 길이
- 체크섬(Checksum): 헤더와 데이터의 손상 검출값
체크섬은 오류를 검출하지만 복구하지 않는다. 손상이 발견된 데이터그램은 일반적으로 폐기된다. IPv4에서는 UDP 체크섬을 사용하지 않을 수 있지만, IPv6에서는 일반적인 UDP 통신에 체크섬이 필요하다.
3.2 데이터그램 전달
송신 애플리케이션이 소켓(Socket)에 데이터를 전달하면 운영체제는 UDP 헤더를 붙인다. IP 계층은 이를 IP 패킷에 담아 목적지 호스트로 전송한다.
애플리케이션 데이터
↓
UDP 헤더 + 데이터
↓
IP 헤더 + UDP 헤더 + 데이터
↓
네트워크 전송수신 호스트는 목적지 포트 번호를 기준으로 데이터를 받을 소켓을 찾는다. 해당 포트에서 대기하는 소켓이 없으면 데이터그램은 전달되지 않으며, 인터넷 제어 메시지 프로토콜(ICMP, Internet Control Message Protocol) 오류가 반환될 수 있다.
UDP 소켓에서 사용하는 connect()는 TCP 연결 수립과 다르다. 핸드셰이크를 수행하지 않고 기본 목적지를 지정하며, 운영체제가 해당 상대의 데이터그램만 받도록 제한하는 역할을 한다.
3.3 신뢰성이 필요할 때
애플리케이션이 신뢰성을 요구하면 UDP 데이터에 별도 정보를 추가해야 한다.
메시지 종류 | 순서 번호 | 전송 시각 | 데이터이를 이용해 다음 기능을 구현할 수 있다.
- 순서 번호(Sequence Number)를 이용한 중복 제거와 순서 복구
- 확인 응답(ACK)을 이용한 수신 확인
- 제한 시간(Timeout)을 이용한 선택적 재전송
- 전송 속도 제한과 혼잡 제어
- 손실되어도 되는 데이터와 재전송할 데이터 구분
이 기능을 전부 직접 구현하면 복잡도가 크게 증가한다. 신뢰성 있는 UDP 기반 전송이 필요하다면 빠른 UDP 인터넷 연결(QUIC, Quick UDP Internet Connections)처럼 검증된 프로토콜을 사용하는 편이 안전하다.
4. 코드 예제
다음 파이썬 프로그램은 같은 파일을 서버와 클라이언트로 실행하는 UDP 에코(Echo) 예제다.
import argparse
import socket
BUFFER_SIZE = 65_535
def run_server(host: str, port: int) -> None:
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
sock.bind((host, port))
print(f"UDP 서버 대기 중: {host}:{port}")
while True:
data, address = sock.recvfrom(BUFFER_SIZE)
message = data.decode("utf-8")
print(f"{address}에서 수신: {message}")
response = f"응답: {message}".encode("utf-8")
sock.sendto(response, address)
def run_client(host: str, port: int, message: str) -> None:
server_address = (host, port)
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
sock.settimeout(2.0)
sock.sendto(message.encode("utf-8"), server_address)
try:
data, address = sock.recvfrom(BUFFER_SIZE)
except TimeoutError:
print("2초 안에 응답을 받지 못했습니다.")
return
print(f"{address}에서 수신: {data.decode('utf-8')}")
def main() -> None:
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest="mode", required=True)
server_parser = subparsers.add_parser("server")
server_parser.add_argument("--host", default="127.0.0.1")
server_parser.add_argument("--port", type=int, default=9000)
client_parser = subparsers.add_parser("client")
client_parser.add_argument("--host", default="127.0.0.1")
client_parser.add_argument("--port", type=int, default=9000)
client_parser.add_argument("message")
args = parser.parse_args()
if args.mode == "server":
run_server(args.host, args.port)
else:
run_client(args.host, args.port, args.message)
if __name__ == "__main__":
main()파일 이름을 udp_echo.py로 저장한 뒤 첫 번째 터미널에서 서버를 실행한다.
python udp_echo.py server두 번째 터미널에서 클라이언트를 실행한다.
python udp_echo.py client "안녕하세요"sendto() 호출 한 번이 UDP 데이터그램 하나를 만든다. recvfrom()은 데이터와 송신자 주소를 함께 반환한다. 응답이 유실될 수 있으므로 클라이언트는 settimeout()으로 무한 대기를 방지한다.
5. 시간 복잡도 또는 성능 특성
길이가 n바이트인 데이터그램을 송수신할 때 데이터 복사와 체크섬 계산 비용은 일반적으로 O(n)이다. 소켓 함수 호출 자체는 고정된 인터페이스 비용이 있지만 실제 전송 시간은 데이터 크기, 네트워크 상태, 버퍼, 장치 성능에 영향을 받는다.
UDP 헤더는 항상 8바이트다. 길이 필드는 16비트이므로 일반적인 UDP 데이터그램의 전체 길이는 최대 65,535바이트다. 최소 20바이트 IPv4 헤더를 사용할 때 UDP 데이터는 이론상 최대 65,507바이트다.
그러나 최대 크기로 보내는 방식은 실무에서 안전하지 않다. 데이터그램이 경로 최대 전송 단위(Path MTU)를 넘으면 IP 단편화(Fragmentation)가 발생할 수 있다. 단편 하나만 손실되어도 원래 데이터그램 전체를 복원할 수 없다.
일반적인 이더넷 최대 전송 단위가 1,500바이트이고 IPv4 헤더가 20바이트라면 단편화 없이 담을 수 있는 UDP 데이터는 최대 1,472바이트다.
1,500 - IPv4 헤더 20 - UDP 헤더 8 = 1,472바이트IPv6 기본 헤더는 40바이트이므로 같은 조건에서 최대 1,452바이트다. 실제 경로에는 더 작은 최대 전송 단위나 추가 헤더가 존재할 수 있으므로 애플리케이션은 여유 있는 데이터그램 크기를 사용하거나 경로 최대 전송 단위 탐색(Path MTU Discovery)을 고려해야 한다.
6. 실무 사용 사례
DNS
도메인 이름 시스템(DNS, Domain Name System)은 짧은 질의와 응답에 UDP를 주로 사용한다. 응답이 없으면 클라이언트가 다시 질의할 수 있다. 큰 응답이나 영역 전송처럼 신뢰성 있는 전송이 필요한 상황에서는 TCP도 사용한다.
실시간 음성·영상
인터넷 전화와 화상 회의는 오래된 데이터의 재전송보다 최신 데이터 전달을 우선한다. 손실된 일부 음성이나 영상 프레임은 건너뛰고 재생을 계속할 수 있다.
실시간 전송 프로토콜(RTP, Real-time Transport Protocol)은 주로 UDP 위에서 순서 번호와 타임스탬프를 제공한다.
온라인 게임
플레이어 위치와 방향처럼 계속 갱신되는 상태는 과거 데이터보다 최신 데이터가 중요하다. 오래된 위치 정보를 재전송하기보다 새 상태를 보내는 편이 지연 시간을 줄인다.
결제 결과나 아이템 획득처럼 손실되면 안 되는 이벤트에는 확인 응답, 재전송, 중복 제거가 별도로 필요하다.
QUIC와 HTTP/3
QUIC는 UDP 위에서 신뢰성, 암호화, 혼잡 제어, 스트림 다중화(Stream Multiplexing)를 제공한다. HTTP/3는 QUIC를 전송 기반으로 사용한다. 운영체제의 TCP 구현을 변경하지 않고 사용자 공간에서 전송 기능을 발전시킬 수 있다는 장점이 있다.
서비스 검색과 모니터링
동일 네트워크의 장치를 찾는 서비스 검색, 간단한 상태 보고, 일부 로그와 지표 전송에도 UDP를 사용한다. 수신자가 느려져도 송신자를 직접 대기시키지 않지만, 과부하 시 데이터가 조용히 유실될 수 있다.
7. 주의할 점
데이터그램 유실을 정상 상황으로 처리한다
UDP 전송 성공은 운영체제가 데이터를 받아들였다는 뜻이지 상대가 수신했다는 뜻이 아니다. 중요한 데이터에는 메시지 식별자, 확인 응답, 제한 시간, 재전송 횟수를 설계한다.
큰 데이터그램을 피한다
큰 데이터그램은 단편화와 손실 가능성을 높인다. 애플리케이션 계층에서 데이터를 작은 조각으로 나눈다면 조각 번호, 전체 조각 수, 재조립 제한 시간도 함께 관리해야 한다.
메시지 경계를 고려한다
수신 버퍼가 데이터그램보다 작으면 남은 부분을 다음 호출에서 이어 받는다고 가정할 수 없다. 운영체제와 소켓 인터페이스에 따라 초과 부분이 잘릴 수 있으므로 충분한 버퍼를 준비하거나 최대 메시지 크기를 제한한다.
중복과 순서 변경을 처리한다
단순히 순서 번호만 비교하면 값의 순환, 클라이언트 재시작, 오래된 패킷 도착을 잘못 처리할 수 있다. 세션 식별자와 순서 번호를 함께 사용하고 허용 가능한 수신 범위를 제한한다.
보안 경계를 검증한다
UDP는 송신자 주소 위조(IP Spoofing)에 악용될 수 있다. 작은 요청으로 큰 응답을 만드는 서버는 반사·증폭 공격(Reflection and Amplification Attack)에 이용될 수 있다.
외부 입력에는 다음 제한을 적용한다.
- 요청 크기와 응답 크기 제한
- 클라이언트별 요청 속도 제한
- 인증되지 않은 요청에 대한 큰 응답 금지
- 데이터 형식과 길이 검증
- 재조립 버퍼와 대기 시간 제한
8. 핵심 정리
- UDP는 연결 수립 없이 독립된 데이터그램을 전달한다.
- 메시지 경계는 유지되지만 전달, 순서, 중복 방지는 보장하지 않는다.
- 헤더는 8바이트이며 출발지 포트, 목적지 포트, 길이, 체크섬을 담는다.
- 낮은 지연 시간과 전송 정책 제어가 중요한 DNS, 실시간 통신, 게임, QUIC에 사용한다.
- 신뢰성이 필요하면 애플리케이션이나 상위 프로토콜이 확인 응답, 재전송, 순서 복구, 혼잡 제어를 제공해야 한다.
- 큰 데이터그램은 IP 단편화 위험이 있으므로 경로 최대 전송 단위를 고려해야 한다.