네트워크 소켓(Socket)이란?

포트와 자주 헷갈리는 소켓이 무엇인지, 프로그램은 소켓으로 어떻게 연결을 맺는지 개념부터 호출 순서까지 정리했습니다.

한눈에 보기

소켓은 네트워크 통신의 한쪽 끝을 프로그램이 다룰 수 있게 만든 접속점입니다. 포트 번호가 "어느 서비스로 갈지"를 가리키는 숫자라면, 소켓은 IP 주소·포트·프로토콜이 결합된 실제 통신 끝점입니다. 아래 8개 항목은 개념(소켓, 포트와의 차이, 소켓 쌍, TCP/UDP)을 차례로 설명하고, 그 아래에서는 프로그램이 소켓을 만들고 연결하는 순서, 역사, 실제 사례, 흔한 오해를 이어서 다룹니다.

🔌

1. 소켓(Socket)이란

소켓은 "IP 주소 + 포트 번호 + 프로토콜(TCP 또는 UDP)"의 조합으로 만들어지는, 네트워크 통신의 양쪽 끝을 나타내는 접속점입니다. 전화로 비유하면 IP 주소는 건물 주소, 포트 번호는 그 건물 안의 내선 번호, 소켓은 실제로 통화가 연결된 하나의 회선이라고 볼 수 있습니다.

🆚

2. 포트와 소켓의 차이

포트 번호는 "어떤 서비스로 연결할지"를 가리키는 하나의 숫자(0~65535)일 뿐이지만, 소켓은 그 포트 번호에 실제 IP 주소와 프로토콜까지 결합해 만들어진 구체적인 연결 하나하나를 뜻합니다. 같은 80번 포트라도 접속한 클라이언트 IP마다 서로 다른 소켓이 만들어져 여러 명이 동시에 같은 웹서버에 접속할 수 있는 것입니다.

🔗

3. 소켓 쌍(Socket Pair)으로 연결을 구분한다

하나의 TCP 연결은 "내 IP:내 포트"와 "상대 IP:상대 포트"로 이루어진 소켓 쌍으로 고유하게 식별됩니다. 이 덕분에 서버는 같은 80번 포트로 수천 명이 동시에 접속해도 각 소켓 쌍을 기준으로 어떤 요청이 어느 사용자의 것인지 정확히 구분할 수 있습니다.

📶

4. TCP 소켓과 UDP 소켓의 차이

TCP 소켓은 통화를 걸듯 먼저 연결을 맺고(3-way 핸드셰이크) 순서와 도착을 보장하며 데이터를 주고받는 방식이고, UDP 소켓은 미리 연결하지 않고 엽서를 보내듯 데이터를 그때그때 전송하는 방식입니다. 웹사이트 접속처럼 정확성이 중요하면 TCP를, 실시간 게임이나 화상통화처럼 속도가 더 중요하면 UDP 기반 소켓을 주로 사용합니다.

🔢

5. 잘 알려진 포트와 임시 포트

서버가 사용하는 80(HTTP), 443(HTTPS) 같은 포트는 누구나 알 수 있도록 정해진 "잘 알려진 포트"입니다. 반면 내 컴퓨터(클라이언트)가 서버에 접속할 때 쓰는 포트는 매번 운영체제가 자동으로 골라주는 임시 포트로, 사용자가 직접 신경 쓸 필요는 없습니다. 임시 포트 범위는 IANA가 권고하는 49152~65535가 기준이지만 운영체제마다 기본값이 달라(예: 리눅스 다수 커널은 32768~60999) 정확한 범위는 각 OS 설정에서 확인해야 합니다.

🏷️

6. 소켓 주소(Socket Address) 표기법

소켓 주소는 흔히 "IP주소:포트번호" 형태로 표기합니다. 예를 들어 192.168.0.10:8080은 192.168.0.10이라는 기기의 8080번 포트를 가리키는 소켓 주소이며, 이 표기법은 서버 설정 파일이나 개발자 도구 화면에서 자주 볼 수 있습니다.

🎧

7. 리스닝(Listening) 소켓과 연결된(Established) 소켓

서버 프로그램이 특정 포트에서 새로운 접속을 기다리고 있는 상태를 리스닝 소켓이라 하고, 클라이언트와 실제로 연결이 맺어져 데이터를 주고받는 상태를 연결된(Established) 소켓이라 합니다. netstat 같은 네트워크 진단 명령어로 현재 어떤 소켓이 리스닝 중이고 어떤 소켓이 연결되어 있는지 직접 확인할 수 있습니다. 프로그래밍 관점에서는 listen()으로 만든 리스닝 소켓이 연결을 기다리고, accept()가 연결 하나마다 새 소켓을 만들어 돌려주므로 리스닝 소켓은 계속 열려 있습니다.

🛡️

8. 방화벽이 통제하는 것도 결국 소켓

방화벽 규칙에서 "특정 포트를 차단한다"고 할 때, 실제로는 그 포트로 새로운 소켓 연결이 만들어지는 것 자체를 막는 것입니다. 소켓 개념을 이해하면 포트포워딩, 방화벽 규칙, 프록시 설정 같은 여러 네트워크 개념이 결국 같은 원리 위에서 동작한다는 점을 알 수 있습니다.

소켓 API는 어디서 왔나: 버클리 소켓

오늘날 프로그램이 네트워크를 쓰는 표준적인 방식인 "소켓 API"는 1983년 공개된 4.2BSD 유닉스에서 시작되어 버클리 소켓(Berkeley sockets)이라고 불립니다(위키백과 기준). 이후 이 인터페이스는 POSIX 표준의 일부가 되어 "POSIX 소켓"과 사실상 같은 말로 쓰이고, 마이크로소프트 윈도우의 Winsock도 이 인터페이스를 거의 그대로 따릅니다. 운영체제가 달라도 소켓 호출의 이름과 순서가 비슷한 이유가 여기에 있습니다.

프로그램이 연결을 맺는 순서

아래는 POSIX 문서와 위키백과에서 확인되는 TCP 연결의 기본 호출 순서입니다.

호출쓰는 쪽하는 일
socket()서버·클라이언트통신 끝점을 만들고 파일 디스크립터를 돌려줍니다(실패 시 -1).
bind()주로 서버소켓에 로컬 주소와 포트를 붙입니다.
listen()서버(TCP)연결을 받을 수 있는 상태로 만들고, backlog로 대기열 길이를 힌트로 지정합니다. 구현체가 값을 더 낮게 조정할 수 있습니다(POSIX).
accept()서버(TCP)대기열에서 연결 하나를 꺼내 그 연결 전용의 새 소켓을 만듭니다. 리스닝 소켓은 계속 열려 있습니다.
connect()클라이언트TCP에서는 서버에 연결을 맺고, UDP에서는 기본 상대 주소를 정합니다.
send()/recv(), sendto()/recvfrom()양쪽데이터를 보내고 받습니다.

아래는 이 순서를 보여주는 짧은 일반 예시(파이썬, 같은 컴퓨터 안에서만 동작하는 에코 서버)입니다. 서버를 먼저 실행한 뒤 다른 창에서 클라이언트를 실행합니다.

# 서버: socket -> bind -> listen -> accept
import socket
srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
srv.bind(("127.0.0.1", 5000))      # 로컬 PC에서만 접속 가능
srv.listen(5)
conn, addr = srv.accept()          # addr = 상대의 (IP, 임시 포트)
conn.sendall(conn.recv(1024))      # 받은 내용을 그대로 돌려줌
conn.close(); srv.close()

# 클라이언트: socket -> connect
import socket
c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
c.connect(("127.0.0.1", 5000))
c.sendall(b"hello")
print(c.recv(1024))
c.close()

여기서 서버의 accept()가 돌려준 addr에 찍히는 상대 포트가 바로 클라이언트에 배정된 임시 포트입니다. 127.0.0.1은 자기 자신을 가리키는 주소이므로 외부에서 접속할 수 없고, 실습용으로 안전합니다. 허락받지 않은 다른 시스템에 접속을 시도하는 행위는 법적 문제가 될 수 있으므로, 실습은 반드시 자신의 컴퓨터 안에서만 하세요.

TCP 소켓과 UDP 소켓 비교

구분TCP (SOCK_STREAM)UDP (SOCK_DGRAM)
연결연결 지향: 먼저 연결을 맺음비연결: 연결 없이 데이터그램 전송
서버 호출bind → listen → acceptbind 후 바로 recvfrom (accept 불필요)
신뢰성바이트 스트림을 오류 정정과 함께 전달순서 뒤바뀜, 중복, 유실이 있을 수 있음(위키백과)
부하상대적으로 큼상대적으로 작음

실제 사례로 보는 소켓

사례 1. 운영체제마다 달랐던 임시 포트 범위

클라이언트가 서버에 접속할 때 쓰는 임시 포트는 IANA가 49152~65535를 권고합니다(RFC 6335). 그러나 위키백과에 정리된 바에 따르면 윈도우 XP 이하는 기본값이 1024~5000이었고, 윈도우 비스타 이후는 IANA 범위를 기본으로 씁니다. 윈도우 서버 2003은 2008년 보안 업데이트 MS08-037 이후 IANA 범위를 쓰게 되었습니다. 리눅스는 다수 커널에서 32768~60999가 기본값이고, /proc/sys/net/ipv4/ip_local_port_range에서 실제 범위를 확인할 수 있습니다. 배울 점은 "임시 포트 49152~65535"를 모든 환경에 적용되는 상수로 외우면 안 된다는 것입니다. 방화벽 규칙이나 동시 접속 설계를 할 때는 대상 OS의 실제 범위를 확인해야 합니다.

사례 2. 하나의 80번 포트에서 수많은 연결을 처리하는 서버의 구조

웹서버는 보통 80이나 443번 포트에 리스닝 소켓 하나를 열어 두고, 새 접속이 들어올 때마다 accept()가 연결 전용의 새 소켓을 만들어 줍니다. 이 새 소켓들은 서버 쪽 IP:포트는 같지만 상대(클라이언트) IP:포트가 다르므로 서로 다른 소켓 쌍으로 구별됩니다. 그래서 포트 번호가 하나여도 연결이 섞이지 않습니다. 이것은 버클리 소켓 API의 기본 설계에서 확인되는 동작이며, 동시 접속자를 처리하는 방식(프로세스, 스레드, 이벤트 기반)은 서버 소프트웨어마다 다릅니다.

직접 확인해 보기

흔한 오해와 정정

한계와 더 알아볼 점

이 글의 호출 순서는 TCP/UDP 기반 인터넷 소켓의 일반적인 형태입니다. 같은 컴퓨터 안의 프로세스끼리 쓰는 유닉스 도메인 소켓처럼 IP·포트를 쓰지 않는 소켓도 있고, 언어와 프레임워크마다 소켓 위에 더 높은 추상화를 얹어 직접 호출할 일이 거의 없는 경우도 많습니다. listen()의 backlog 값이 실제로 어떻게 해석되는지는 구현체에 따라 달라질 수 있습니다(POSIX 문서는 힌트라고 규정).

포트 번호 자체가 궁금하다면

소켓을 이루는 요소 중 하나인 포트 번호 자체를 더 자세히 알고 싶다면포트 번호 완전정복도 함께 확인해보세요.

실시간 양방향 통신에 쓰이는 웹소켓과는 다릅니다

이름이 비슷한 "웹소켓(WebSocket)"은 이 페이지에서 다룬 운영체제 수준의 일반적인 소켓 개념이 아니라, 브라우저와 서버가 지속적인 양방향 통신을 하기 위해 만들어진 별도의 응용 계층 프로토콜입니다. 웹소켓 자체가 궁금하다면 웹소켓(WebSocket)이란? 기초 개념 정리를 확인해보세요.

함께 읽으면 좋은 가이드

소켓 개념을 이해하면 방화벽(Firewall)이란? 기초 개념 정리과포트포워딩 설정하는 방법이 왜 필요한지 더 쉽게 이해할 수 있습니다. TCP와 UDP의 차이는 TCP와 UDP 차이 가이드에서 더 자세히 볼 수 있습니다.

자주 묻는 질문

소켓 번호는 사용자가 직접 정하나요?

서버가 사용하는 잘 알려진 포트(80, 443 등)는 프로그램이나 관리자가 지정하지만, 클라이언트가 접속할 때 쓰는 임시 포트는 운영체제가 자동으로 배정하므로 사용자가 신경 쓸 필요가 없습니다.

소켓이 부족해지는 경우도 있나요?

네, 매우 많은 연결을 동시에 짧은 시간에 맺고 끊는 서버에서는 임시 포트가 일시적으로 부족해지는 "소켓 고갈" 현상이 나타날 수 있습니다. 이런 경우 서버 설정에서 연결 재사용(Keep-Alive) 설정을 조정해 완화하기도 합니다.

bind()는 클라이언트에서도 꼭 호출해야 하나요?

일반적으로 클라이언트는 bind()를 생략하고 connect()를 호출하면 운영체제가 임시 포트를 자동으로 배정합니다. 특정 로컬 포트를 쓰고 싶을 때만 bind()를 먼저 호출합니다.

listen()의 backlog를 크게 주면 동시 접속자를 그만큼 받을 수 있나요?

그렇지 않을 수 있습니다. POSIX 문서에 따르면 backlog는 대기열 길이에 대한 힌트이고 구현체가 최대값으로 낮춰 적용할 수 있습니다. 또 대기열은 아직 accept()되지 않은 연결의 수를 말하므로 전체 동시 접속자 수와는 다른 개념입니다.

127.0.0.1로 연 서버에는 왜 다른 컴퓨터에서 접속이 안 되나요?

127.0.0.1은 자기 자신(루프백)을 가리키는 주소라서 같은 컴퓨터 안에서만 닿습니다. 외부에서 접속하게 하려면 다른 주소에 바인드해야 하지만, 그 경우 방화벽과 접근 통제를 먼저 점검해야 합니다.