서비스 포트를 열었다고 했지만 클라이언트는 여전히 연결하지 못합니다. TCP와 UDP의 동작 차이, 포트 번호의 의미를 모르면 같은 "포트"라는 단어 아래 다른 문제를 섞게 됩니다.
포트는 애플리케이션으로 들어가는 문입니다. 어떤 프로토콜의 어떤 문인지 먼저 구분해야 합니다.
TCP vs UDP와 포트 체계
네트워크에서 두 컴퓨터가 데이터를 주고받을 때, 단순히 IP 주소만으로는 어떤 애플리케이션이 받을지 알 수 없습니다. **포트(Port)**와 **전송 프로토콜(TCP/UDP)**이 이 문제를 해결합니다. 이 챕터에서는 TCP의 신뢰성 메커니즘인 3-Way Handshake, UDP의 빠른 통신 원리, 그리고 Well-known Port 체계를 이해하고 nc(netcat)으로 직접 통신을 실습합니다.
- 1TCP 3-Way Handshake와 4-Way Teardown 연결 수립·종료 과정
- 2TCP의 신뢰성 메커니즘: 순서 번호, ACK, 재전송, 흐름 제어
- 3UDP의 특성과 TCP 대비 장단점 비교
- 4DNS·NTP·스트리밍 등 UDP가 적합한 서비스 유형
- 5Well-known Port 체계와 주요 서비스 포트 번호
- 6nc(netcat)로 TCP/UDP 포트 통신 직접 실습
nc -h 2>&1 | head -5ss -tlnpnc -l 9000터미널 B에서 'nc localhost 9000'으로 접속하면 양방향 통신 실습 가능
TCP — 신뢰성을 보장하는 연결 지향 프로토콜
마이크로서비스를 배포했는데 클러스터 내부에서는 헬스체크가 통과하지만 외부 모니터링은 타임아웃을 보고합니다. 방화벽도, 포트도, 프로세스도 문제없습니다. ss -tan 출력을 보면 SYN_RECV 상태로 쌓인 연결들이 보이는데, 이 상태가 무엇을 뜻하는지 해석조차 못 합니다. TCP의 연결 수립 과정을 이해하지 못하면 이 출력이 아무 의미 없는 숫자로만 보입니다.

TCP란 무엇인가
**TCP(Transmission Control Protocol)**는 데이터를 순서대로, 빠짐없이, 오류 없이 전달하도록 설계된 전송 계층 프로토콜입니다. 이를 위해 연결 수립, 흐름 제어, 오류 감지 및 재전송 메커니즘을 갖추고 있습니다.
3-Way Handshake — 연결 수립
TCP 통신을 시작하기 전, 반드시 3단계 핸드셰이크로 연결을 수립합니다.
클라이언트 서버
│ │
│ ──── SYN (seq=100) ───────────► │
│ "연결하고 싶어" │
│ │
│ ◄── SYN-ACK (seq=200, ack=101) ─ │
│ "알겠어, 나도 연결 준비됐어" │
│ │
│ ──── ACK (ack=201) ────────────► │
│ "확인. 이제 통신 시작하자" │
│ │
│ ═══════ 데이터 전송 가능 ══════════ │
각 단계의 의미:
- SYN: 클라이언트가 연결을 요청하며 초기 시퀀스 번호(ISN)를 전달
- SYN-ACK: 서버가 요청을 수락하고, 자신의 ISN을 전달하며 클라이언트의 SYN을 ACK
- ACK: 클라이언트가 서버의 SYN을 ACK하며 연결 수립 완료
연결 종료 — 4-Way Teardown
TCP 연결 종료는 4단계를 거칩니다:
클라이언트 서버
│ ──── FIN ──────────────────────► │ "더 보낼 데이터 없음"
│ ◄─── ACK ───────────────────── │ "FIN 받았음"
│ ◄─── FIN ───────────────────── │ "서버도 종료"
│ ──── ACK ──────────────────────► │ "확인"
TCP의 신뢰성 메커니즘
TCP가 "빠짐없이, 순서대로" 데이터를 보장하는 것은 여러 메커니즘이 조합된 결과입니다. 각 기능이 담당하는 역할을 정리하면 TCP가 왜 느리지만 신뢰할 수 있는지 이해됩니다.
| 기능 | 설명 |
|---|---|
| 순서 번호(Sequence Number) | 패킷에 번호를 붙여 순서 보장 |
| 확인 응답(ACK) | 받은 패킷을 확인하고, 미수신 시 재전송 요청 |
| 재전송 | 일정 시간 내 ACK 없으면 자동 재전송 |
| 흐름 제어(Flow Control) | 수신 버퍼 크기(Window Size)에 맞춰 전송 속도 조절 |
| 혼잡 제어(Congestion Control) | 네트워크 혼잡 시 전송 속도 자동 감소 |
TCP를 사용하는 주요 프로토콜
HTTP/HTTPS — TCP 80/443 (웹)
SSH — TCP 22 (원격 접속)
FTP — TCP 20/21 (파일 전송)
SMTP — TCP 25/587 (이메일 발송)
MySQL — TCP 3306 (데이터베이스)
PostgreSQL — TCP 5432 (데이터베이스)
Redis — TCP 6379 (캐시)
UDP와 Well-known Port 체계
DNS 쿼리가 간헐적으로 실패합니다. 서버는 살아있고 포트 53도 열려 있는데 왜 안 되는지 이해가 안 됩니다. 원인은 UDP 패킷 유실이었습니다. TCP라면 자동으로 재전송했겠지만 DNS는 UDP를 씁니다. UDP가 왜 신뢰성을 포기하는지, 어떤 서비스가 UDP를 쓰는지 알면 이런 간헐적 실패의 원인을 훨씬 빠르게 좁힐 수 있습니다.

UDP — 속도 우선, 신뢰성 포기
**UDP(User Datagram Protocol)**는 TCP의 연결 수립, 순서 보장, 재전송 메커니즘을 모두 제거하고 최소한의 기능만 가진 프로토콜입니다.
[UDP 통신 — 그냥 보냄]
클라이언트 서버
│ │
│ ──── 데이터 ───────────────► │
│ ──── 데이터 ───────────────► │ (순서 보장 없음)
│ ──── 데이터 ───────────────► │ (손실되어도 재전송 없음)
│ │
TCP vs UDP 비교
어떤 상황에서 TCP를 쓰고 어떤 상황에서 UDP를 쓸지는 각 프로토콜의 특성 차이에서 결정됩니다.
| 특성 | TCP | UDP |
|---|---|---|
| 연결 수립 | 필요 (3-Way Handshake) | 불필요 |
| 순서 보장 | 보장 | 미보장 |
| 재전송 | 자동 재전송 | 없음 |
| 오류 검사 | 헤더 + 데이터 | 선택적 체크섬 |
| 속도 | 상대적으로 느림 | 빠름 |
| 오버헤드 | 높음 (헤더 20~60바이트) | 낮음 (헤더 8바이트) |
| 적합한 용도 | 파일 전송, 웹, DB | DNS, 스트리밍, 게임 |
UDP가 적합한 서비스
DNS (UDP 53)
클라이언트 → DNS 서버: "google.com이 뭐야?" (1패킷)
DNS 서버 → 클라이언트: "142.250.196.110" (1패킷)
요청과 응답이 각 1패킷으로 끝나는 단순한 질의응답 구조에서 TCP 연결 수립(3-Way Handshake)은 불필요한 오버헤드입니다. DNS는 UDP 53을 사용합니다.
NTP (UDP 123)
시간 동기화는 단발성 요청/응답이며, 일부 패킷 손실 시 재전송보다 다시 질의하는 것이 빠릅니다.
실시간 영상/음성 (RTP, UDP 기반)
1초에 30프레임을 전송하는 영상에서 한 프레임이 손실되어도 다음 프레임을 보여주는 것이 훨씬 자연스럽습니다. TCP 재전송으로 인한 지연은 화상통화를 불가능하게 만들 수 있습니다.
온라인 게임
캐릭터 위치 정보는 100ms마다 갱신됩니다. 오래된 위치 데이터를 재전송받는 것보다 최신 데이터를 새로 받는 것이 게임 경험에 유리합니다.
Well-known Port 체계
포트 번호는 0~65535 범위이며 세 구간으로 나뉩니다:
| 범위 | 이름 | 특징 |
|---|---|---|
| 0 ~ 1023 | Well-known Ports | 표준 서비스, root 권한 필요 |
| 1024 ~ 49151 | Registered Ports | 등록된 애플리케이션 |
| 49152 ~ 65535 | Dynamic/Ephemeral | 클라이언트 임시 포트 |
필수 암기 Well-known Ports
| 포트 | 프로토콜 | 서비스 |
|---|---|---|
| 20, 21 | TCP | FTP (데이터, 제어) |
| 22 | TCP | SSH (보안 원격 접속) |
| 23 | TCP | Telnet (비암호화 원격) |
| 25 | TCP | SMTP (이메일 발송) |
| 53 | UDP (+ TCP) | DNS |
| 67, 68 | UDP | DHCP |
| 80 | TCP | HTTP |
| 110 | TCP | POP3 (이메일 수신) |
| 123 | UDP | NTP (시간 동기화) |
| 143 | TCP | IMAP (이메일 수신) |
| 443 | TCP | HTTPS |
| 587 | TCP | SMTP Submission (이메일 발송, TLS) |
| 3306 | TCP | MySQL |
| 5432 | TCP | PostgreSQL |
| 6379 | TCP | Redis |
| 8080 | TCP | HTTP 대체 (개발/프록시) |
| 27017 | TCP | MongoDB |
Ephemeral Port
클라이언트가 서버에 연결할 때, 운영체제가 자동으로 49152~65535 범위에서 임시 포트를 할당합니다.
클라이언트 IP:PORT 서버 IP:PORT
192.168.1.10:54321 ────► 93.184.216.34:443
↑
임시 포트 (ephemeral)
OS가 자동 할당
# 실습 디렉토리 준비
mkdir -p /tmp/networking/part1/exam_5 && cd /tmp/networking/part1/exam_5
# 현재 클라이언트 포트 범위 확인
$ cat /proc/sys/net/ipv4/ip_local_port_range
32768 60999
- 핵심 출력—명령 결과에서 성공/실패를 가르는 값을 먼저 확인합니다
- 대상 식별—IP, 포트, 인터페이스, 프로세스명처럼 다음 조치를 결정하는 필드를 봅니다
- 다음 분기—결과가 기대와 다르면 어느 계층을 이어서 점검할지 정합니다
목표
nc(netcat)로 간단한 TCP 서버를 열고 클라이언트로 접속하여, 실제 포트 통신이 어떻게 이루어지는지 체험합니다.
전제 조건
# nc 설치 확인
$ which nc
# 없으면:
$ sudo apt install netcat-openbsd # Ubuntu/Debian
$ sudo yum install nmap-ncat # CentOS/RHEL
단계별 실습
1단계: TCP 서버 열기 (터미널 1)
# 8080 포트에서 연결 대기
$ nc -l 8080
# 또는 다음 옵션과 함께:
$ nc -l -p 8080 -v
# Listening on 0.0.0.0 8080
이 명령어를 실행하면 터미널이 대기 상태로 멈춥니다. 연결이 들어오기를 기다리는 중입니다.
2단계: 클라이언트로 접속 (터미널 2)
새 터미널을 열어 접속합니다:
# 같은 서버에서 접속 (loopback)
$ nc 127.0.0.1 8080
# 또는 서버 IP로 원격 접속
$ nc 10.0.0.5 8080
3단계: 양방향 메시지 전송
터미널 2에서 입력하면 터미널 1에서 수신됩니다:
[터미널 2 - 클라이언트] [터미널 1 - 서버]
$ nc 127.0.0.1 8080
Hello, Server! Hello, Server! ← 수신
←────────
Hi, Client!
Hi, Client! ← 수신
4단계: 파일 전송 테스트
# 서버: 파일 수신 준비
$ nc -l 9000 > received_file.txt
# 클라이언트: 파일 전송
$ nc 127.0.0.1 9000 < /etc/hostname
# 전송 완료 후 Ctrl+D로 종료
# 서버 측에서 수신 확인
$ cat received_file.txt
5단계: 연결 종료
- 클라이언트:
Ctrl+D(EOF 전송) 또는Ctrl+C - 서버: 클라이언트 연결 종료 후 자동 종료, 또는
Ctrl+C
확인 포인트
# 연결 중 상태 확인 (다른 터미널에서)
$ ss -tnp | grep 8080
# LISTEN 0 1 0.0.0.0:8080 0.0.0.0:* 서버 대기 중
# ESTAB 0 0 127.0.0.1:8080 127.0.0.1:54321 연결 수립됨
목표
nc를 클라이언트 모드로 사용하여 원격 서버의 특정 포트가 열려 있는지 확인합니다. 방화벽 정책 확인이나 서비스 응답 테스트에 활용됩니다.
단계별 실습
1단계: TCP 포트 개방 확인
# -z: 데이터 전송 없이 연결 시도만
# -v: 자세한 출력
# -w 3: 3초 타임아웃
# 포트가 열려 있는 경우
$ nc -zv google.com 443
# Connection to google.com 443 port [tcp/https] succeeded!
# 포트가 닫혀 있는 경우
$ nc -zv google.com 8888
# nc: connect to google.com port 8888 (tcp) failed: Connection refused
2단계: UDP 포트 확인
# -u: UDP 모드
$ nc -zvu 8.8.8.8 53
# Connection to 8.8.8.8 53 port [udp/domain] succeeded!
3단계: 여러 포트 범위 스캔
# 20~25 포트 순차 확인
$ nc -zv 192.168.1.1 20-25
# 출력:
# nc: connect to 192.168.1.1 port 20 failed: Connection refused
# nc: connect to 192.168.1.1 port 21 failed: Connection refused
# Connection to 192.168.1.1 port 22 (tcp) succeeded! ← SSH 열림
4단계: 서비스 배너 확인
# SSH 서버 배너 확인 (연결 후 즉시 출력)
$ nc 10.0.0.5 22
# SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.6
# HTTP 서버 직접 요청
$ echo -e "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n" | nc example.com 80
# HTTP/1.0 200 OK
# Content-Type: text/html
# ...
5단계: 방화벽 정책 테스트 시나리오
# 방화벽 규칙 추가 전 테스트
$ nc -zv app-server 3306
# nc: connect to app-server port 3306 failed: Connection refused
# 방화벽 규칙 추가 후 재테스트
$ nc -zv app-server 3306
# Connection to app-server port 3306 (tcp) succeeded!
nc vs telnet vs curl 비교
| 도구 | 강점 | 약점 |
|---|---|---|
nc | TCP/UDP 모두 지원, 스크립팅 용이 | TLS 미지원 |
telnet | 단순, 배너 확인 용이 | UDP 미지원, 구식 |
curl | HTTPS 지원, 다양한 프로토콜 | 단순 포트 체크엔 과함 |
목표
실제 운영 환경에서 방화벽 ACL(Access Control List) 정책을 요청할 때 필요한 정보를 올바르게 명시하는 방법을 익힙니다.
시나리오
애플리케이션 서버(10.0.1.20)가 다음 서비스에 접근해야 합니다:
- 데이터베이스 서버(10.0.2.10)의 MySQL(3306/TCP)
- 외부 DNS 서버(8.8.8.8)의 DNS(53/UDP)
- 외부 HTTPS API(api.partner.com의 443/TCP)
올바른 ACL 요청서 작성
잘못된 요청 (흔한 실수)
"10.0.1.20에서 10.0.2.10 포트 3306 허용해 주세요"
→ TCP인지 UDP인지 명시 안 됨!
→ 방화벽 담당자가 TCP만 추가하면 이후 문제 발생 가능
올바른 요청
방화벽 ACL 요청
출발지: 10.0.1.20/32
목적지: 10.0.2.10/32
포트: 3306
프로토콜: TCP
방향: Outbound (10.0.1.20 → 10.0.2.10)
목적: 애플리케이션 서버 → MySQL DB 접근
---
출발지: 10.0.1.20/32
목적지: 8.8.8.8/32
포트: 53
프로토콜: UDP ← DNS는 반드시 UDP!
방향: Outbound
목적: DNS 질의
---
출발지: 10.0.1.20/32
목적지: ANY (api.partner.com 해당 IP 대역)
포트: 443
프로토콜: TCP
방향: Outbound
목적: 파트너 API 연동
프로토콜 확인 방법
# 서비스별 기본 프로토콜 확인
$ grep mysql /etc/services
# mysql 3306/tcp
# mysql 3306/udp (등록되어 있지만 실제로는 TCP만 사용)
$ grep domain /etc/services
# domain 53/tcp
# domain 53/udp ← UDP가 기본
$ grep https /etc/services
# https 443/tcp
열린 포트와 프로토콜 확인
# 서버에서 열린 포트 확인 (TCP)
$ ss -tlnp
# State Recv-Q Send-Q Local Address:Port
# LISTEN 0 128 0.0.0.0:22 TCP 22 (SSH)
# LISTEN 0 80 0.0.0.0:3306 TCP 3306 (MySQL)
# UDP 포트 확인
$ ss -ulnp
# State Recv-Q Send-Q Local Address:Port
# UNCONN 0 0 0.0.0.0:53 UDP 53 (DNS)
# UNCONN 0 0 0.0.0.0:123 UDP 123 (NTP)
증상
# DNS 질의가 타임아웃
$ dig @10.0.0.53 myapp.internal.com
# ;; connection timed out; no servers could be reached
# 또는 특정 도구에서만 DNS 실패
# curl은 되는데 dig는 안 됨 (또는 반대)
원인: TCP 53을 사용했거나 방화벽에서 TCP 53만 허용
방화벽 ACL에 TCP 53만 허용되고 UDP 53이 차단된 경우, 또는 dig나 nslookup 옵션에 TCP가 강제 지정된 경우 발생합니다.
# 잘못된 ACL 요청의 예:
출발지: 10.0.0.0/24
목적지: 10.0.0.53/32
포트: 53
프로토콜: TCP ← UDP가 빠짐!
진단 방법
# UDP 53으로 직접 테스트
$ dig @10.0.0.53 myapp.internal.com
# 타임아웃
# TCP 53으로 테스트
$ dig @10.0.0.53 myapp.internal.com +tcp
# 응답 옴!
# → 방화벽에서 UDP 53만 차단됨, 반대로 TCP는 열림
# UDP로 nc 테스트
$ nc -zuv 10.0.0.53 53
# nc: connect to 10.0.0.53 port 53 (udp) failed: Connection refused
# → UDP 53 차단 확인
해결 방법
방화벽 ACL 수정
기존:
출발지: 10.0.0.0/24 → 10.0.0.53:53/TCP ALLOW
추가 필요:
출발지: 10.0.0.0/24 → 10.0.0.53:53/UDP ALLOW
임시 우회 (TCP 강제)
방화벽 수정 전 임시로 TCP DNS를 사용:
# dig에서 TCP 강제 지정
$ dig @10.0.0.53 myapp.internal.com +tcp
# /etc/resolv.conf에 options 추가
$ echo "options use-vc" | sudo tee -a /etc/resolv.conf
# use-vc: 모든 DNS 질의를 TCP로 전송
DNS에서 TCP를 사용하는 정당한 경우
| 상황 | 이유 |
|---|---|
| Zone Transfer (AXFR) | 대용량 Zone 데이터 전송 |
| 응답 크기 > 512바이트 | UDP 한계 초과 시 TCP로 재시도 |
| DNSSEC 응답 | 서명 데이터로 응답 크기 큼 |
| DNS over TLS (DoT) | TCP 853 사용 |
# Zone Transfer 테스트 (TCP 53 사용)
$ dig @ns1.example.com example.com AXFR
예방 방법
방화벽 ACL 요청 시 DNS 관련 규칙은 반드시 TCP/UDP 양쪽을 명시합니다:
포트 53, 프로토콜: TCP AND UDP 모두 허용
증상
# 서버에서 로컬 확인
$ nc -zv 127.0.0.1 8080
# Connection to 127.0.0.1 8080 port [tcp] succeeded!
# 외부에서 접속 시도 (다른 서버에서)
$ nc -zv 10.0.0.5 8080
# nc: connect to 10.0.0.5 port 8080 (tcp) failed: Connection refused
원인 1: 서비스가 Localhost에만 바인딩
# 바인딩 주소 확인
$ ss -tlnp | grep 8080
# LISTEN 0 128 127.0.0.1:8080 ... ← 127.0.0.1만 바인딩!
# ↑
# 외부 접속 불가
서비스 설정에서 0.0.0.0:8080 대신 127.0.0.1:8080으로 바인딩되어 있습니다.
해결: 서비스 설정에서 바인딩 주소를 0.0.0.0 또는 서버의 실제 IP로 변경:
# 예: Python HTTP 서버
$ python3 -m http.server 8080 --bind 0.0.0.0
# 예: 애플리케이션 설정 파일
# server.host=0.0.0.0 (또는 server.bind-address=0.0.0.0)
원인 2: 방화벽(firewalld/iptables)에서 포트 차단
이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.
# firewalld 확인 (RHEL/CentOS)
$ sudo firewall-cmd --list-ports
# 22/tcp 80/tcp 443/tcp ← 8080 없음!
# 포트 추가
$ sudo firewall-cmd --add-port=8080/tcp --permanent
$ sudo firewall-cmd --reload
# iptables 확인 (직접 확인 필요 시)
$ sudo iptables -L INPUT -n | grep 8080
원인 3: 클라우드 보안 그룹 미설정
AWS EC2, GCP VM 등에서는 OS 방화벽 외에 **보안 그룹(Security Group)**에서도 포트를 허용해야 합니다.
# AWS 콘솔 → EC2 → 보안 그룹 → 인바운드 규칙 추가
유형: 사용자 지정 TCP
포트 범위: 8080
소스: 0.0.0.0/0 (또는 특정 IP)
진단 순서
외부 접속 실패
│
▼
서버에서 ss -tlnp | grep [포트]
├── 0.0.0.0:[포트] → 바인딩 OK → 방화벽 확인
└── 127.0.0.1:[포트] → 바인딩 문제 → 서비스 설정 변경
│
▼
OS 방화벽 확인
├── firewall-cmd --list-ports
└── iptables -L INPUT -n
│
▼
클라우드 보안 그룹 확인 (AWS/GCP/Azure)
마이크로서비스 환경의 포트 관리
마이크로서비스 아키텍처에서는 서비스마다 포트를 할당하고 관리해야 합니다.
# docker-compose.yml에서 포트 매핑
services:
auth-service:
ports:
- "3001:3001" # HOST:CONTAINER TCP 기본
catalog-service:
ports:
- "3002:3002"
# 데이터베이스는 외부 노출 최소화
postgres:
ports:
- "127.0.0.1:5432:5432" # localhost에서만 접근 가능
포트 충돌 시 진단:
# 어떤 프로세스가 포트 사용 중인지 확인
$ ss -tlnp | grep :3001
$ lsof -i :3001
Kubernetes NetworkPolicy 작성 시
쿠버네티스 NetworkPolicy에서 포트와 프로토콜 명시:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-mysql
spec:
podSelector:
matchLabels:
app: web
egress:
- to:
- podSelector:
matchLabels:
app: mysql
ports:
- protocol: TCP ← 프로토콜 명시 필수
port: 3306
- ports: ← DNS는 UDP 필수!
- protocol: UDP
port: 53
- protocol: TCP
port: 53
이 기술이 필요한 직군
| 직군 | 활용 상황 |
|---|---|
| 백엔드 개발자 | 서비스 포트 설계, 방화벽 ACL 요청, 로컬 개발 환경 구성 |
| DevOps/SRE | 포트 충돌 진단, 방화벽 정책 검증, 서비스 헬스체크 구현 |
| 보안 엔지니어 | 불필요한 포트 노출 감사, ACL 정책 리뷰 |
| 클라우드 엔지니어 | VPC 보안 그룹 설계, NLB/ALB 리스너 설정 |
알아두면 차별화되는 지식
QUIC과 HTTP/3 — UDP 443
HTTP/3은 TCP 대신 UDP 기반의 QUIC 프로토콜을 사용합니다. 기존 방화벽에서 TCP 443만 허용하면 HTTP/3이 작동하지 않아 HTTP/2로 폴백됩니다.
# QUIC(HTTP/3) 지원 여부 확인
$ curl -v --http3 https://cloudflare.com 2>&1 | grep "HTTP/"
SO_REUSEPORT — 포트 공유
여러 프로세스나 스레드가 동일 포트를 공유하는 기술:
# nginx 멀티 워커가 80 포트 공유하는 예
$ ss -tlnp | grep :80
# LISTEN 0 511 0.0.0.0:80 processes:(("nginx",pid=1234,...),("nginx",pid=1235,...))
TIME_WAIT 상태
TCP 연결 종료 후 약 2MSL(보통 60초) 동안 소켓이 TIME_WAIT 상태로 남습니다. 대량의 단기 연결을 처리하는 서버에서 포트 고갈이 발생할 수 있습니다:
# TIME_WAIT 연결 수 확인
$ ss -tan state time-wait | wc -l
# TIME_WAIT 빠른 재사용 설정
$ sudo sysctl net.ipv4.tcp_tw_reuse=1
핵심 명령어 요약
# nc 서버 모드 (포트 열기)
nc -l [포트]
nc -l -p [포트] -v
# nc 클라이언트 모드 (접속)
nc [IP] [포트]
nc -zv [IP] [포트] # 포트 개방 확인 (데이터 전송 없음)
nc -zuv [IP] [포트] # UDP 포트 확인
# 포트 현황 확인
ss -tlnp # TCP LISTEN 포트 + 프로세스
ss -ulnp # UDP LISTEN 포트 + 프로세스
ss -tnp # 현재 TCP 연결 상태
# 서비스별 기본 포트 확인
grep [서비스명] /etc/services
체크리스트
방화벽 ACL 요청 전 확인 사항:
- 포트 번호를 확인했는가?
- 프로토콜이 TCP인지 UDP인지 명시했는가?
- DNS(53)는 UDP와 TCP 모두 포함했는가?
- 출발지/목적지 IP 또는 CIDR을 정확히 명시했는가?
- 단방향인지 양방향인지 확인했는가?
-
ss -tlnp로 서비스가 올바른 주소에 바인딩되었는지 확인했는가?