소켓(Socket)은 네트워크 통신의 종단점(Endpoint)을 추상화한 소프트웨어 인터페이스로, 1983년 UC Berkeley에서 개발한 4.2BSD 유닉스 운영체제에서 처음 등장하여 현재까지 인터넷 통신의 근간을 이루는 핵심 기술이다. IP 주소와 포트 번호의 조합으로 네트워크 상의 고유한 통신 지점을 식별하며, 프로세스 간 데이터 교환을 가능하게 하는 표준화된 API를 제공한다.
소켓의 역사와 발전
Berkeley Sockets의 탄생
Berkeley Sockets(BSD Sockets)은 1982년 BSD UNIX 4.1에서 처음 소개되었으며, 1986년 BSD UNIX 4.3에서 개정된 버전이 현재까지 널리 사용되고 있다. 처음에는 사실상(de facto) 표준이었으나, 이후 POSIX 사양의 공식 구성 요소로 채택되어 거의 모든 운영체제에서 동일한 인터페이스로 네트워크 프로그래밍을 할 수 있게 되었다.
소켓 인터페이스가 표준화되기 이전에는 각 운영체제와 네트워크 스택마다 고유한 네트워크 프로그래밍 인터페이스를 사용했기 때문에 이식성이 매우 낮았으며, Berkeley Sockets의 등장은 플랫폼 독립적인 네트워크 애플리케이션 개발의 기반을 마련했다. Windows에서는 Winsock(Windows Sockets)이라는 이름으로 BSD 소켓 API를 채택했고, 이로 인해 유닉스 계열과 Windows 간에 거의 동일한 코드로 네트워크 프로그래밍이 가능해졌다.
소켓의 기본 개념
소켓이란?
소켓은 네트워크를 통해 데이터를 송수신하기 위한 추상화된 인터페이스로, 프로토콜(TCP/UDP), IP 주소, 포트 번호의 세 가지 요소로 고유하게 식별된다. 전화 통신에서 전화기가 음성 신호를 전기 신호로 변환하는 것처럼, 소켓은 애플리케이션 데이터를 네트워크 패킷으로 변환하고 그 역과정을 수행한다.
소켓은 크게 두 가지 역할로 구분되는데, 서버 소켓은 특정 IP 주소와 포트에서 클라이언트의 연결 요청을 수신 대기(listen)하고, 클라이언트 소켓은 서버 소켓에 연결을 시도(connect)하여 통신 채널을 형성한다. 연결이 수립되면 양쪽 모두 동일한 방식으로 데이터를 송수신할 수 있으며, 운영체제는 소켓을 파일 디스크립터로 관리하기 때문에 파일 입출력과 유사한 방식으로 네트워크 통신을 처리할 수 있다.
전송 계층 프로토콜: TCP vs UDP
TCP와 UDP는 OSI 모델의 4계층(전송 계층)에서 동작하는 프로토콜로, 각각 다른 특성과 용도를 가지며 소켓 프로그래밍에서 소켓 타입을 결정하는 핵심 요소이다.
TCP (Transmission Control Protocol)
TCP의 핵심 특성
TCP는 연결 지향적(Connection-oriented)이고 신뢰성 있는(Reliable) 전송 프로토콜로, 데이터가 순서대로 정확하게 도착하는 것을 보장한다. 3-way handshake를 통해 연결을 수립하고, 오류 감지 및 재전송, 흐름 제어, 혼잡 제어 메커니즘을 제공하여 데이터 무결성을 보장한다.
TCP 연결은 SYN → SYN-ACK → ACK의 3-way handshake 과정을 거쳐 수립되며, 이 과정에서 양측의 초기 시퀀스 번호(ISN)가 교환되고 수신 윈도우 크기와 같은 연결 매개변수가 협상된다. 연결이 수립된 후에는 각 세그먼트에 시퀀스 번호가 부여되어 수신 측에서 순서를 재조립할 수 있고, 확인 응답(ACK)을 통해 전송 성공 여부를 확인하며, 타임아웃 발생 시 자동으로 재전송이 이루어진다.
| 특성 | 설명 |
|---|---|
| 헤더 크기 | 20-60 바이트 (옵션 포함 시 최대 60) |
| 데이터 단위 | 세그먼트(Segment) |
| 연결 수립 | 3-way handshake 필요 |
| 신뢰성 보장 | 순서 보장, 오류 감지/재전송, 흐름/혼잡 제어 |
| 사용 사례 | HTTP, HTTPS, FTP, SMTP, SSH, 데이터베이스 연결 |
UDP (User Datagram Protocol)
UDP의 핵심 특성
UDP는 비연결형(Connectionless)이고 신뢰성을 보장하지 않는(Unreliable) 전송 프로토콜로, 연결 설정 과정 없이 즉시 데이터를 전송할 수 있다. 오버헤드가 적어 지연 시간이 짧고, 실시간성이 중요한 애플리케이션에 적합하다.
UDP는 연결 수립이나 종료 과정이 없기 때문에 첫 번째 데이터그램부터 바로 전송할 수 있으며, 각 데이터그램은 독립적으로 처리되어 순서가 보장되지 않는다. 패킷 손실이 발생해도 재전송하지 않으므로 애플리케이션 계층에서 필요한 경우 직접 신뢰성 메커니즘을 구현해야 하지만, 이러한 단순성 덕분에 TCP보다 훨씬 낮은 지연 시간을 달성할 수 있다.
| 특성 | 설명 |
|---|---|
| 헤더 크기 | 8 바이트 고정 |
| 데이터 단위 | 데이터그램(Datagram) |
| 연결 수립 | 불필요 (비연결형) |
| 신뢰성 보장 | 없음 (애플리케이션에서 처리 필요) |
| 사용 사례 | DNS, DHCP, VoIP, 비디오 스트리밍, 온라인 게임, QUIC |
TCP와 UDP 선택 기준
| 요구사항 | 권장 프로토콜 |
|---|---|
| 데이터 무결성이 필수 | TCP |
| 낮은 지연 시간 필요 | UDP |
| 순서 보장 필요 | TCP |
| 일부 손실 허용 가능 | UDP |
| 브로드캐스트/멀티캐스트 | UDP |
| 대용량 파일 전송 | TCP |
소켓 프로그래밍의 핵심 함수
소켓 프로그래밍에서 사용되는 주요 시스템 콜은 socket, bind, listen, accept, connect이며, 서버와 클라이언트는 이 함수들을 정해진 순서로 호출하여 연결을 수립하고 데이터를 교환한다.
socket()
socket() 함수는 새로운 소켓을 생성하고 해당 소켓을 참조하는 파일 디스크립터를 반환하며, 도메인(AF_INET for IPv4, AF_INET6 for IPv6), 타입(SOCK_STREAM for TCP, SOCK_DGRAM for UDP), 프로토콜을 인자로 받아 어떤 종류의 통신을 수행할지 결정한다. 서버와 클라이언트 모두 통신을 시작하기 전에 이 함수를 호출해야 한다.
bind()
bind() 함수는 소켓에 로컬 IP 주소와 포트 번호를 할당하여 네트워크 상에서 해당 소켓의 위치를 지정하며, 주로 서버 측에서 특정 포트에서 연결을 수신하기 위해 사용한다. 클라이언트는 일반적으로 운영체제가 사용 가능한 포트를 자동으로 할당하도록 bind()를 생략한다.
listen()
listen() 함수는 TCP 서버 소켓을 능동(active) 모드에서 수동(passive) 모드로 전환하여 들어오는 연결 요청을 수신 대기하도록 하며, 두 번째 인자로 대기 큐(backlog)의 크기를 지정한다. 이 함수가 호출된 후에야 클라이언트의 connect() 요청이 서버에 도달할 수 있다.
accept()
accept() 함수는 대기 큐에서 첫 번째 연결 요청을 꺼내어 해당 연결을 위한 새로운 소켓을 생성하고 반환하며, 원래의 수신 대기 소켓은 계속해서 추가 연결을 받을 수 있다. 이 함수는 연결 요청이 있을 때까지 블로킹되며, 반환된 새 소켓을 통해 클라이언트와의 실제 데이터 교환이 이루어진다.
connect()
connect() 함수는 클라이언트에서 사용되며 지정된 서버 주소와 포트로 연결을 시도하고, TCP의 경우 3-way handshake를 수행하여 연결을 수립한다. UDP 소켓에서도 connect()를 호출할 수 있는데, 이 경우 실제 연결이 수립되는 것이 아니라 기본 목적지 주소가 설정되어 이후 send() 호출 시 주소를 생략할 수 있게 된다.
통신 흐름 다이어그램

클라이언트-서버 아키텍처
클라이언트-서버 모델
클라이언트-서버 아키텍처는 네트워크 애플리케이션의 가장 기본적인 분산 컴퓨팅 모델로, 서비스를 요청하는 클라이언트와 서비스를 제공하는 서버로 역할이 분리된다. 이 모델은 리소스의 중앙 집중화, 보안 관리 용이성, 확장성 측면에서 장점을 가지며, 웹, 이메일, 데이터베이스 등 대부분의 인터넷 서비스가 이 구조를 따른다.
클라이언트와 서버는 동일한 물리적 머신에서 실행될 수도 있고 네트워크를 통해 분리된 하드웨어에서 실행될 수도 있으며, 하나의 서버가 동시에 수천 개의 클라이언트 연결을 처리하는 것이 일반적이다. 서버는 항상 실행 중이면서 클라이언트의 요청을 기다리고, 클라이언트는 필요할 때 서버에 연결하여 서비스를 요청한 후 연결을 종료하는 패턴으로 동작한다.
동시성 처리 모델
서버가 여러 클라이언트를 동시에 처리하기 위한 방법으로는 멀티프로세스, 멀티스레드, 이벤트 기반(논블로킹 I/O), 그리고 이들을 조합한 하이브리드 모델이 있다. 최근에는 epoll(Linux), kqueue(BSD), IOCP(Windows) 같은 운영체제 수준의 이벤트 알림 메커니즘을 활용한 이벤트 기반 모델이 높은 동시성과 효율성으로 널리 사용되며, Node.js, Nginx, Redis 등이 이 방식을 채택하고 있다.
WebSocket: 웹을 위한 양방향 통신
WebSocket이란?
WebSocket은 2011년 IETF가 RFC 6455로 표준화한 양방향 통신 프로토콜로, 단일 TCP 연결 위에서 전이중(Full-duplex) 통신 채널을 제공한다. HTTP의 단방향 요청-응답 모델의 한계를 극복하고 서버에서 클라이언트로 데이터를 푸시할 수 있어, 실시간 웹 애플리케이션에 이상적이다.
소켓과 WebSocket의 관계
| 구분 | TCP/UDP 소켓 | WebSocket |
|---|---|---|
| OSI 계층 | 4계층 (전송 계층) | 7계층 (애플리케이션 계층) |
| 기반 프로토콜 | IP | TCP + HTTP(핸드셰이크) |
| 포트 | 임의 포트 사용 가능 | 80(ws), 443(wss) |
| 프록시/방화벽 | 별도 설정 필요 | HTTP 호환으로 대부분 통과 |
| 메시지 프레이밍 | 직접 구현 필요 | 프로토콜에서 제공 |
| 브라우저 지원 | 불가 (직접 접근) | 네이티브 API 제공 |
WebSocket은 TCP 소켓을 기반으로 하지만 HTTP와의 호환성을 위해 설계된 상위 계층 프로토콜이다. 연결 수립 시 HTTP Upgrade 핸드셰이크를 사용하여 기존 HTTP 인프라(프록시, 로드 밸런서, 방화벽)를 통과할 수 있고, 연결이 수립된 후에는 HTTP 오버헤드 없이 경량화된 프레임 형식으로 데이터를 교환한다.
WebSocket 사용 사례
WebSocket은 채팅 애플리케이션, 실시간 협업 도구(Google Docs, Figma), 주식 시세/암호화폐 거래소, 온라인 게임, 라이브 스포츠 스코어, IoT 대시보드 등 서버에서 클라이언트로 즉시 데이터를 푸시해야 하는 모든 상황에서 활용된다. 기존의 롱 폴링(Long Polling)이나 Server-Sent Events(SSE)보다 낮은 지연 시간과 양방향 통신 기능을 제공한다.
마치며
소켓은 1983년 Berkeley Sockets로 시작하여 40년 이상 네트워크 프로그래밍의 표준 인터페이스로 자리 잡았으며, TCP와 UDP라는 두 가지 전송 프로토콜 위에서 다양한 애플리케이션의 통신 요구를 충족시키고 있다. TCP는 신뢰성과 순서 보장이 필요한 곳에, UDP는 실시간성과 낮은 지연이 중요한 곳에 각각 사용되며, 이 선택이 애플리케이션의 성능과 특성을 결정한다. WebSocket은 이러한 저수준 소켓의 개념을 웹 환경에 맞게 추상화하여, 브라우저에서도 실시간 양방향 통신을 가능하게 만든 기술이다.