아웃바운드 소켓의 핵심은 연결을 누가 시작했는가입니다. 집이나 회사 안의 프로그램이 바깥 서버로 먼저 연결했다면 아웃바운드 연결입니다. 이 이름만 보고 데이터도 안에서 밖으로만 간다고 생각하기 쉽지만, 연결이 성립한 뒤에는 양쪽 모두 같은 소켓으로 데이터를 보낼 수 있습니다.
연결은 안에서 밖으로 시작하고, 성립한 소켓의 데이터는 양방향으로 오갑니다.
아웃바운드 연결 데모에서 안에서 먼저 연결을 재생하면
첫 CONNECT는 안쪽 PC에서 바깥 서버로 향합니다. 그 뒤 NOTICE는 반대 방향으로,
STATUS는 다시 바깥 방향으로 이동합니다.
이번 편은 연결 원리까지만 다룹니다
앞의 소켓 완전 기초에서는 서버가 포트에서 기다리고
클라이언트가 connect()로 찾아가는 흐름을 배웠습니다. 이번 편은 그 연결이 방화벽과
NAT가 있는 네트워크 경계를 어떻게 지나가는지에 집중합니다.
| 이론 2/3에서 다루는 것 | 뒤의 응용 5단계에서 다루는 것 |
|---|---|
| 누가 새 연결을 시작하는가 | 메시지가 처리됐는지 어떻게 확인하는가 |
| 새 인바운드 연결과 기존 세션의 차이 | 끊긴 전송과 화면 상태를 어떻게 복구하는가 |
| 연결 뒤 데이터가 양방향인 이유 | 여러 서버와 지연이 있는 환경에서 어떻게 동작하는가 |
따라서 이 편에서는 재시도 횟수, 작업 체크포인트, 메시지 중복 제거 같은 운영 규칙을 설계하지 않습니다. 먼저 통로가 생기는 원리만 분명하게 구분합니다.
outbound는 연결 시작 방향입니다
안쪽 프로그램이 바깥 서버의 IP와 포트로 connect()를 호출한다고 생각해 봅시다.
연결 시작: 안쪽 프로그램 ── CONNECT ──▶ 바깥 서버
연결 성립: 안쪽 프로그램 ◀════ 데이터 ════▶ 바깥 서버
첫 줄이 outbound입니다. 두 번째 줄은 이미 성립한 연결의 데이터 흐름입니다. TCP 연결과 그 위의 WebSocket은 양쪽 프로그램 모두 읽고 쓸 수 있는 통로이므로, 서버가 데이터를 보낼 때마다 안쪽 PC로 새로 접속하는 것이 아닙니다.
| 질문 | 확인할 방향 |
|---|---|
| 누가 연결을 열었나? | 안쪽 프로그램 → 바깥 서버 |
| 연결 뒤 누가 데이터를 보내나? | 안쪽 프로그램 ⇄ 바깥 서버 |
연결 시작 방향과 send·receive 방향은 서로 다른 질문입니다.
새 인바운드 연결과 기존 세션은 다릅니다
집과 회사의 PC는 흔히 사설 주소를 사용하고 방화벽이나 NAT 뒤에 있습니다. 공개 주소, 포트 전달과 허용 규칙이 없는 상태에서 바깥 서버가 안쪽 PC로 새 연결을 바로 시작하면 도달하지 못합니다.
반대로 안쪽 프로그램이 먼저 바깥으로 연결하면 방화벽과 NAT는 그 연결에 필요한 상태를 관리할 수 있습니다. 이후 바깥 서버가 보내는 데이터는 별도의 새 인바운드 연결이 아니라, 이미 성립한 세션의 반대 방향 데이터입니다.
새 인바운드 연결: 바깥 서버 ── 새 CONNECT ──▶ 안쪽 PC ✕
기존 세션의 데이터: 바깥 서버 ── DATA ───────▶ 안쪽 PC ✓
두 번째가 가능하다고 해서 모든 목적지와 포트가 자동으로 허용되는 것은 아닙니다. 실제 환경에서는 조직의 아웃바운드 정책, 프록시와 목적지 허용 규칙을 별도로 확인해야 합니다.
WSS 연결에서는 무엇이 차례로 생길까요
데모는 wss://control.example.com/agent로 연결하는 상황을 단순화했습니다.
- 안쪽 프로그램이 바깥 서버로 TCP 연결을 시작합니다.
- TLS handshake로 암호화된 통로를 만듭니다.
- WebSocket handshake가 끝나면 지속해서 쓸 세션이 성립합니다.
- 프로그램이 열린 세션 안에서 자신을 식별합니다.
- 이후 양쪽이 같은 세션으로 데이터를 보냅니다.
wss는 WebSocket 통신을 TLS로 보호한다는 뜻입니다. 실제 제품에서는 서버 인증서
검증과 프로그램 인증도 필요하지만, 아웃바운드라는 방향 이름 자체가 인증이나 권한을
보장하지는 않습니다.
같은 원리는 여러 프로그램에서 보입니다
- 장비가 먼저 연결해 지표를 보내고 설정 알림을 받는 상태 수집
- 데스크톱 프로그램이 먼저 연결해 진행 상황을 주고받는 원격 작업
- 기기가 먼저 연결해 승인된 설정을 받는 장비 관리
- 브라우저가 WebSocket을 열고 서버 알림을 받는 실시간 화면
여기서 공통점은 구체적인 작업 내용이 아니라 안쪽 프로그램이 연결을 먼저 열고, 바깥 서버가 그 세션을 통해 반대 방향 데이터도 보낸다는 연결 구조입니다.
응용 규칙은 이론 3/3을 마친 뒤 이어집니다
아웃바운드 연결은 통로만 제공합니다. 그 통로를 운영하려면 데이터 성격에 따라 서로 다른 규칙이 필요합니다.
아래 5개는 언어별 소켓 런타임까지 이론 3단계를 마친 뒤 진행하는 응용 과정입니다.
- 전달 보장 — ACK·메시지 ID·재시도로 중복 부작용을 막습니다.
- 흐름 제어 — 느린 수신자 앞에서 멈추고 파일을 이어받습니다.
- 상태 동기화 — 버전과 스냅숏으로 놓친 화면 상태를 맞춥니다.
- 서버 확장 — 브로커와 저장소로 여러 서버 사이를 잇습니다.
- 지연 대응 — 늦게 온 과거 상태를 버리고 화면을 부드럽게 표시합니다.
이 문제들은 아웃바운드 연결에서만 생기는 것이 아닙니다. 인바운드로 받아들인 소켓, 브라우저 WebSocket과 다른 실시간 연결에서도 각각 설계해야 하는 응용 계층의 규칙입니다.
방화벽을 켜고 양쪽에서 걸어 보세요
두 방향을 따로 보세요
연결 방향과 데이터 방향은 어떻게 다를까요?
읽는 순서① 상황 선택→② 실험 시작→③ 화살표 방향과 ‘인바운드 포트 닫힘’ 확인
- 1안에서 연결
- 2세션 성립
- 3서버가 전송
- 4안쪽이 응답
- 5방향 구분
① 연결 만들기: 안쪽 PC → 바깥 서버② 연결된 뒤: 데이터 ← · 데이터 →
지금 상태
메시지 기록
실험을 시작하면 연결과 데이터 흐름이 한 줄씩 쌓여요.
첫 시나리오는 안쪽에서 연결한 뒤 데이터가 양방향으로 오가는 모습을 보여 줍니다. 두 번째에서는 바깥의 새 연결과 이미 열린 세션을 비교합니다.
원리 세 가지만
아웃바운드 소켓이 하는 일
안쪽 PC의 클라이언트 프로그램이 WSS 443 같은 허용된 바깥 경로를 사용합니다. PC마다 공개 포트를 만들 필요가 없습니다.
outbound는 연결을 누가 시작했는지의 말입니다. 연결 뒤에는 서버도 같은 TCP/WebSocket 세션으로 데이터를 보낼 수 있습니다.
ACK·재시도·중복 제거·상태 복구는 아웃바운드 연결 위에 별도로 만드는 응용 규칙입니다.
원격 작업 말고도
같은 연결 패턴을 쓰는 곳
진단 수집, 배포 보조, 백업 실행
장비 지표, 로그, heartbeat
대시보드 갱신, 작업 진행률
설정 동기화, 승인된 업데이트
이론과 응용의 경계
이 편은 통로가 생기는 원리까지만 다룹니다.
통로 위의 메시지를 어떻게 보장하고 복구할지는 뒤의 소켓 응용 5단계에서 각각 실험합니다.
- 2/3이론 · 연결 방향connect 시작점과 양방향 세션
- 1/5응용 · 전달 보장ACK · 재시도 · 메시지 ID
- 2/5응용 · 흐름 제어backpressure · 청크 이어받기
- 3~5응용 · 복구와 확장상태 · 서버 · 지연 대응
데모만 따로 보려면 전체 화면으로 열기.
- 안에서 먼저 연결에서 첫
CONNECT화살표가 안쪽에서 바깥으로 가는지 봅니다. - 세션이 성립한 뒤
NOTICE와STATUS화살표가 서로 반대인지 확인합니다. - 밖에서 직접 연결로 바꿔 새 인바운드 연결이 차단되는지 봅니다.
- 안쪽 프로그램이 아웃바운드 연결을 열면 세션이 생기는지 확인합니다.
- 인바운드 포트는 닫힌 상태에서도 기존 세션의 데이터가 양방향인지 봅니다.
나가는 연결은 몇 개까지 만들 수 있을까
아웃바운드 연결에는 눈에 안 보이는 자원이 하나 붙습니다. 출발지 포트 번호입니다. 바깥으로 연결할 때마다 운영체제가 남는 번호를 하나씩 빌려줍니다.
이 글을 쓰는 리눅스에서 그 범위를 확인해 봤습니다.
$ cat /proc/sys/net/ipv4/ip_local_port_range
32768 60999
60999 − 32768 + 1 = 28,232개입니다. 65,535개가 아닙니다.
"포트가 65,535개니 6만 연결까지"라는 오해
여기서 두 가지가 어긋납니다.
첫째, 실제로 쓸 수 있는 범위가 위처럼 더 좁습니다. 낮은 번호들은 서버가 귀를 여는 용도로 비워 둡니다.
둘째, 이 28,232라는 한계는 "총 연결 수"가 아니라 "같은 상대에게 거는 연결 수" 입니다. TCP 연결은 네 가지 값의 조합으로 구분되기 때문입니다.
(출발 IP, 출발 포트, 목적 IP, 목적 포트)
목적지가 다르면 출발 포트를 재사용해도 서로 다른 연결입니다. 그래서
A 서버:443으로 28,232개를 열어 한계에 부딪혀도, B 서버:443으로는 다시
28,232개를 열 수 있습니다.
정리하면 이렇습니다.
| 상황 | 한계 |
|---|---|
| 한 대상(IP:포트)에 연결 | 약 28,232개 |
| 여러 대상에 연결 | 대상마다 다시 28,232개 |
| 서버로서 받는 연결 | 이 범위와 무관 (포트 하나로 다 받음) |
마지막 줄이 중요합니다. 받는 쪽은 이 제약을 받지 않습니다. 443 포트 하나로 수만 개의 연결을 받을 수 있습니다. 구분은 상대방의 IP·포트가 해 주니까요.
끊어도 바로 안 돌려줍니다
한 가지 더 있습니다. 연결을 닫아도 포트가 즉시 반납되지 않습니다. 지금 이 노트북의 소켓 상태를 세어 보니 이랬습니다.
TIME-WAIT 18
LISTEN 15
ESTAB 10
연결이 끝난 소켓(TIME-WAIT)이 살아 있는 것보다 많습니다. 늦게 도착하는
패킷이 다음 연결에 섞이지 않도록 일정 시간 자리를 잡아 두기 때문입니다. 그래서
짧은 연결을 아주 빠르게 반복하는 프로그램은, 동시 연결 수가 적어도 포트가
모자랄 수 있습니다.
이 값들은 직접 확인할 수 있습니다.
cat /proc/sys/net/ipv4/ip_local_port_range # 빌려줄 수 있는 번호 범위
ss -tan | awk 'NR>1{print $1}' | sort | uniq -c # 상태별 소켓 수
방향을 헷갈리지 않으려면
- outbound는 데이터를 보내는 방향이 아니라 새 연결을 시작한 방향입니다.
- 새 인바운드 연결과 이미 성립한 세션의 반대 방향 데이터는 다릅니다.
- 방화벽 안쪽 프로그램이 먼저 연결하면 공개 인바운드 포트 없이 지속 세션을 만들 수 있습니다.
- 전달 보장·이어받기·상태 복구·확장·지연 처리는 별도의 응용 규칙입니다.
다음 이론 편에서는 같은 소켓 서버를 Python·Node.js·Go·Rust가 어떻게 다르게 처리하는지 언어별 소켓 런타임으로 이어집니다.