본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2025. 12. 5. · 9 Views
전송 계층과 포트 완벽 가이드
네트워크의 전송 계층과 포트 개념을 초급 개발자도 이해할 수 있도록 설명합니다. IP의 한계부터 포트 번호, NAT, 포트 포워딩, ICMP까지 실무에서 반드시 알아야 할 핵심 개념을 다룹니다.
목차
- IP의_한계와_전송_계층의_역할
- 포트란_무엇인가
- Well-known_Registered_Dynamic_포트
- 포트_기반_NAT_동작
- NAPT_Network_Address_Port_Translation
- 포트_포워딩_개념
- ICMP_프로토콜_이해
1. IP의 한계와 전송 계층의 역할
김개발 씨는 회사에서 처음으로 서버 개발을 맡게 되었습니다. IP 주소만 있으면 통신이 될 줄 알았는데, 선배가 "포트 번호도 지정해야지"라고 합니다.
왜 IP 주소만으로는 부족한 걸까요?
IP 프로토콜은 데이터를 목적지까지 전달하는 역할만 합니다. 마치 택배 기사가 아파트 건물까지만 배송하고, 몇 호인지는 모르는 것과 같습니다.
전송 계층은 바로 이 "몇 호"를 찾아주는 역할을 담당합니다.
다음 코드를 살펴봅시다.
import socket
# IP만으로는 부족합니다 - 포트가 필요합니다
server_ip = "192.168.1.100"
server_port = 8080 # 어떤 애플리케이션인지 지정
# 소켓 생성 - 전송 계층의 핵심
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# IP + 포트를 함께 지정해야 연결 가능
sock.connect((server_ip, server_port))
print(f"연결 성공: {server_ip}:{server_port}")
# 데이터 전송
sock.send(b"Hello, Server!")
sock.close()
김개발 씨는 입사 후 처음으로 백엔드 서버를 개발하게 되었습니다. 네트워크 기초를 공부하면서 IP 주소가 컴퓨터의 고유한 주소라는 것까지는 이해했습니다.
그런데 코드를 작성하다 보니 이상한 점을 발견했습니다. "어?
왜 IP 주소 뒤에 콜론(:)이랑 숫자가 붙어 있지?" 선배 박시니어 씨가 김개발 씨의 화면을 보더니 설명을 시작했습니다. "그게 바로 포트 번호야.
IP 주소만으로는 부족하거든." 생각해보면 당연한 이야기입니다. 하나의 컴퓨터에서는 여러 프로그램이 동시에 실행됩니다.
웹 브라우저도 켜져 있고, 카카오톡도 켜져 있고, 음악 스트리밍도 하고 있습니다. 이 모든 프로그램이 동시에 인터넷을 사용하고 있는데, 외부에서 데이터가 도착하면 어떤 프로그램에게 전달해야 할까요?
IP 프로토콜의 역할은 여기까지입니다. IP는 데이터를 목적지 컴퓨터까지 배달하는 것이 전부입니다.
마치 택배 기사가 "서울시 강남구 테헤란로 123번길 아파트"까지만 배송하고, 정확히 몇 동 몇 호인지는 모르는 것과 같습니다. 바로 이 한계를 해결하기 위해 전송 계층이 존재합니다.
전송 계층은 OSI 7계층에서 4번째 계층으로, IP 계층 바로 위에 위치합니다. 대표적인 프로토콜로는 TCP와 UDP가 있습니다.
전송 계층의 핵심 역할은 프로세스 간 통신을 가능하게 하는 것입니다. 같은 컴퓨터에서 실행 중인 여러 프로그램 중 정확히 어떤 프로그램에게 데이터를 전달할지 결정합니다.
이것을 멀티플렉싱과 디멀티플렉싱이라고 부릅니다. 위의 코드를 살펴보면, socket.connect() 함수에 IP 주소와 포트 번호를 함께 전달하고 있습니다.
이 두 가지 정보가 모두 있어야만 정확한 목적지 프로그램에 데이터를 전달할 수 있습니다. 전송 계층은 또한 신뢰성 있는 데이터 전송을 보장합니다.
IP 프로토콜은 "최선형(Best Effort)" 서비스라서 데이터가 손실되거나 순서가 뒤바뀌어도 신경 쓰지 않습니다. 하지만 TCP 같은 전송 계층 프로토콜은 데이터가 손실되면 재전송하고, 순서가 뒤바뀌면 다시 정렬해줍니다.
박시니어 씨의 설명을 들은 김개발 씨는 고개를 끄덕였습니다. "아, 그래서 항상 IP:PORT 형태로 쓰는 거였군요!" 그렇습니다.
네트워크 통신에서 IP 주소와 포트 번호는 마치 주소와 호수처럼 함께 사용되어야 정확한 목적지를 찾을 수 있습니다.
실전 팁
💡 - IP 주소는 컴퓨터를, 포트 번호는 프로그램을 식별합니다
- TCP는 신뢰성을, UDP는 속도를 우선시합니다
- 서버 개발 시 항상 IP와 포트를 함께 지정하세요
2. 포트란 무엇인가
김개발 씨가 netstat 명령어를 실행해보니 수많은 포트 번호가 나왔습니다. 80, 443, 3306, 8080...
이 숫자들은 대체 무엇을 의미하는 걸까요? 왜 하필 이런 번호들을 사용하는 걸까요?
**포트(Port)**는 컴퓨터 내에서 실행 중인 프로세스를 식별하는 16비트 숫자입니다. 0부터 65535까지 사용할 수 있으며, 마치 아파트의 호수처럼 각 프로그램에게 고유한 번호를 부여합니다.
다음 코드를 살펴봅시다.
import socket
# 서버 소켓 생성
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 포트 번호 8080에 바인딩
# 이제 이 프로그램은 8080번 포트의 "주인"이 됩니다
server.bind(('0.0.0.0', 8080))
server.listen(5)
print("서버가 8080 포트에서 대기 중입니다...")
# 클라이언트 연결 대기
while True:
client, addr = server.accept()
print(f"연결됨: {addr[0]}:{addr[1]}") # IP:포트 출력
client.send(b"Welcome!")
client.close()
김개발 씨는 서버 프로그램을 실행하려다가 에러를 만났습니다. "Address already in use"라는 메시지였습니다.
이미 다른 프로그램이 그 포트를 사용하고 있다는 뜻이었습니다. "포트가 정확히 뭐길래 이런 에러가 나는 거죠?" 박시니어 씨가 화이트보드에 그림을 그리며 설명했습니다.
"포트는 쉽게 말해서 프로그램의 '문' 같은 거야. 외부에서 데이터가 들어올 때 어떤 문으로 들어갈지 결정하는 번호지." 기술적으로 포트는 16비트 정수입니다.
따라서 0부터 65535까지, 총 65536개의 포트를 사용할 수 있습니다. 각 포트는 특정 시점에 하나의 프로세스만 점유할 수 있습니다.
비유를 들어보겠습니다. 대형 건물에 여러 회사가 입주해 있다고 생각해보세요.
건물 주소(IP 주소)는 하나지만, 각 회사는 서로 다른 호실(포트)을 사용합니다. 택배가 도착하면 건물 주소로 먼저 찾아오고, 그 다음 호실 번호를 보고 정확한 회사에 전달됩니다.
네트워크 통신에서도 마찬가지입니다. 클라이언트가 서버에 접속할 때는 목적지 IP 주소와 목적지 포트 번호를 함께 지정합니다.
서버는 해당 포트에서 대기하고 있다가 요청이 오면 처리합니다. 위의 코드에서 server.bind(('0.0.0.0', 8080))가 바로 이 과정입니다.
이 코드는 운영체제에게 "8080번 포트를 내가 쓸게"라고 선언하는 것입니다. 일단 바인딩이 완료되면, 다른 프로그램은 이 포트를 사용할 수 없습니다.
클라이언트 쪽도 포트를 사용합니다. 다만 클라이언트는 보통 포트를 직접 지정하지 않습니다.
운영체제가 자동으로 사용 가능한 포트를 할당해줍니다. 이것을 **임시 포트(Ephemeral Port)**라고 부릅니다.
소켓 프로그래밍에서 통신의 양 끝점은 항상 IP:포트 조합으로 식별됩니다. 이 조합을 소켓 주소라고 부릅니다.
TCP 연결은 출발지 소켓 주소와 목적지 소켓 주소, 이 네 가지 값(출발지 IP, 출발지 포트, 목적지 IP, 목적지 포트)으로 고유하게 식별됩니다. 김개발 씨가 만난 "Address already in use" 에러는 이미 다른 프로그램이 8080 포트를 점유하고 있어서 발생한 것이었습니다.
해결 방법은 간단합니다. 다른 포트 번호를 사용하거나, 기존 프로그램을 종료하면 됩니다.
"그럼 아무 번호나 써도 되는 건가요?" 김개발 씨가 물었습니다. 박시니어 씨가 고개를 저었습니다.
"아니, 포트 번호에도 규칙이 있어. 그건 다음에 알려줄게."
실전 팁
💡 - 포트 충돌 에러가 나면 netstat -an 명령어로 사용 중인 포트를 확인하세요
- 개발 시에는 보통 3000, 8000, 8080 같은 번호를 많이 사용합니다
- 하나의 포트에 여러 연결이 가능한 건 TCP 연결이 4-튜플로 식별되기 때문입니다
3. Well-known Registered Dynamic 포트
김개발 씨는 웹 서버는 80번, 데이터베이스는 3306번을 사용한다는 것을 배웠습니다. 그런데 왜 하필 이 번호들일까요?
누가 이렇게 정한 걸까요?
포트 번호는 세 가지 범위로 나뉩니다. Well-known 포트(0-1023)는 HTTP, FTP 같은 표준 서비스가 사용하고, Registered 포트(1024-49151)는 특정 애플리케이션이 등록하여 사용하며, Dynamic 포트(49152-65535)는 클라이언트가 임시로 사용합니다.
다음 코드를 살펴봅시다.
# 자주 사용되는 Well-known 포트들
well_known_ports = {
20: "FTP (데이터 전송)",
21: "FTP (제어)",
22: "SSH (보안 원격 접속)",
23: "Telnet",
25: "SMTP (이메일 발송)",
53: "DNS (도메인 이름 해석)",
80: "HTTP (웹)",
443: "HTTPS (보안 웹)",
}
# Registered 포트 예시
registered_ports = {
3306: "MySQL",
5432: "PostgreSQL",
6379: "Redis",
8080: "HTTP 대체 포트",
27017: "MongoDB",
}
# Dynamic/Private 포트: 49152 - 65535
# 운영체제가 클라이언트에게 자동 할당
박시니어 씨가 김개발 씨에게 질문했습니다. "웹 브라우저에서 naver.com을 입력하면 어떤 포트로 접속할까?" "음...
80번이요?" "맞아. 그런데 왜 80번인지 알아?" 김개발 씨는 대답하지 못했습니다.
포트 번호는 아무렇게나 정해진 것이 아닙니다. **IANA(Internet Assigned Numbers Authority)**라는 국제 기구에서 포트 번호를 관리합니다.
포트 번호는 크게 세 가지 범위로 나뉩니다. 첫 번째는 Well-known 포트입니다.
0번부터 1023번까지의 범위로, 역사적으로 중요한 서비스들이 사용합니다. HTTP는 80번, HTTPS는 443번, SSH는 22번을 사용합니다.
이 범위의 포트를 사용하려면 보통 관리자(root) 권한이 필요합니다. "왜 관리자 권한이 필요한 거예요?" 김개발 씨가 물었습니다.
이유는 보안 때문입니다. 만약 아무나 80번 포트에서 서버를 실행할 수 있다면, 악의적인 사용자가 가짜 웹 서버를 띄워서 사용자를 속일 수 있습니다.
그래서 운영체제는 1024번 미만의 포트는 특별히 보호합니다. 두 번째는 Registered 포트입니다.
1024번부터 49151번까지의 범위입니다. 특정 회사나 프로젝트가 IANA에 등록하여 사용하는 포트입니다.
MySQL은 3306번, PostgreSQL은 5432번, MongoDB는 27017번을 사용합니다. 이 포트들은 공식적으로 등록되어 있지만, 반드시 따라야 하는 건 아닙니다.
개발 환경에서 흔히 쓰는 8080번도 Registered 포트입니다. 80번을 쓰려면 관리자 권한이 필요하니까, 개발할 때는 8080번을 대신 사용하는 것입니다.
세 번째는 Dynamic 포트 또는 Private 포트입니다. 49152번부터 65535번까지의 범위입니다.
클라이언트가 서버에 접속할 때 운영체제가 이 범위에서 임시 포트를 자동으로 할당합니다. 연결이 끝나면 포트는 반환됩니다.
웹 브라우저로 네이버에 접속한다고 생각해보세요. 브라우저는 운영체제로부터 임시 포트(예: 52341)를 할당받습니다.
그리고 네이버 서버의 443번 포트로 연결합니다. 이 연결은 "내 컴퓨터:52341 <-> 네이버:443"으로 식별됩니다.
"그럼 제가 서버를 만들 때는 어떤 포트를 써야 하나요?" 김개발 씨가 물었습니다. 박시니어 씨가 대답했습니다.
"개발 환경에서는 보통 3000, 5000, 8000, 8080 같은 Registered 포트 범위를 써. 운영 환경에서 웹 서버를 띄울 때는 80이나 443을 쓰고.
Well-known 포트는 피하는 게 좋아. 충돌이 날 수 있거든."
실전 팁
💡 - 개발 시에는 1024번 이상의 포트를 사용하세요 (관리자 권한 불필요)
- 운영 환경에서는 Nginx 같은 리버스 프록시가 80/443을 담당하고, 애플리케이션은 뒤에서 다른 포트를 사용합니다
- 포트 번호는 문서화해두면 팀원들이 이해하기 쉽습니다
4. 포트 기반 NAT 동작
김개발 씨 회사의 모든 컴퓨터가 하나의 공인 IP를 공유한다고 합니다. 그런데 어떻게 각 컴퓨터가 개별적으로 인터넷을 사용할 수 있는 걸까요?
그 비밀은 바로 NAT에 있습니다.
**NAT(Network Address Translation)**은 사설 IP 주소를 공인 IP 주소로 변환하는 기술입니다. 가정이나 회사의 여러 기기가 하나의 공인 IP를 공유할 수 있게 해주며, 포트 번호를 활용해 각 연결을 구분합니다.
다음 코드를 살펴봅시다.
# NAT 테이블 시뮬레이션
class NATTable:
def __init__(self, public_ip):
self.public_ip = public_ip
self.table = {} # 내부 -> 외부 매핑
self.next_port = 40000
def translate_outbound(self, private_ip, private_port, dest_ip, dest_port):
# 사설 IP:포트를 공인 IP:새포트로 변환
key = (private_ip, private_port, dest_ip, dest_port)
if key not in self.table:
self.table[key] = self.next_port
self.next_port += 1
nat_port = self.table[key]
print(f"NAT 변환: {private_ip}:{private_port} -> {self.public_ip}:{nat_port}")
return self.public_ip, nat_port
def translate_inbound(self, nat_port):
# 응답 패킷을 원래 사설 IP로 되돌림
for key, port in self.table.items():
if port == nat_port:
return key[0], key[1] # private_ip, private_port
return None
김개발 씨는 집에서 노트북, 스마트폰, 태블릿을 동시에 사용합니다. 세 기기 모두 인터넷에 연결되어 있는데, 공유기를 확인해보니 공인 IP는 하나뿐입니다.
어떻게 이게 가능한 걸까요? "NAT 덕분이야." 박시니어 씨가 설명을 시작했습니다.
**NAT(Network Address Translation)**은 말 그대로 네트워크 주소를 변환하는 기술입니다. 인터넷 초창기에는 모든 컴퓨터가 고유한 공인 IP 주소를 가졌습니다.
하지만 인터넷이 폭발적으로 성장하면서 IPv4 주소가 부족해졌습니다. IPv4는 약 43억 개의 주소만 제공하는데, 전 세계 기기 수는 이를 훨씬 넘어섰습니다.
이 문제를 해결하기 위해 사설 IP 주소가 도입되었습니다. 192.168.x.x, 10.x.x.x, 172.16.x.x ~ 172.31.x.x 대역은 사설 IP로 예약되어 있습니다.
이 주소들은 인터넷에서 직접 라우팅되지 않고, 같은 네트워크 내에서만 사용됩니다. 그렇다면 사설 IP를 가진 기기가 어떻게 인터넷과 통신할까요?
바로 NAT이 중간에서 주소를 변환해줍니다. 예를 들어보겠습니다.
김개발 씨의 노트북(192.168.1.10)이 네이버(223.130.200.107)에 접속한다고 가정합시다. 노트북에서 보낸 패킷의 출발지는 192.168.1.10입니다.
하지만 이 주소는 인터넷에서 통하지 않습니다. 공유기(NAT 장비)가 이 패킷을 받으면, 출발지 IP를 공인 IP(예: 211.100.50.30)로 바꿉니다.
동시에 출발지 포트도 새로운 번호(예: 40001)로 바꾸고, 이 매핑 정보를 NAT 테이블에 기록합니다. 네이버 서버는 211.100.50.30:40001에서 요청이 왔다고 생각하고, 같은 주소로 응답을 보냅니다.
공유기가 이 응답을 받으면, NAT 테이블을 참조하여 원래 목적지인 192.168.1.10으로 전달합니다. 이 과정에서 포트 번호가 핵심 역할을 합니다.
공유기는 각 연결마다 다른 포트 번호를 할당합니다. 노트북이 40001번, 스마트폰이 40002번, 태블릿이 40003번을 사용하면, 응답이 돌아왔을 때 포트 번호를 보고 어떤 기기에게 전달할지 알 수 있습니다.
위의 코드는 이 NAT 동작을 간단히 시뮬레이션한 것입니다. translate_outbound 메서드가 나가는 패킷의 주소를 변환하고, translate_inbound 메서드가 들어오는 패킷을 원래 기기로 되돌립니다.
NAT 덕분에 우리는 하나의 공인 IP로 수십, 수백 대의 기기를 인터넷에 연결할 수 있습니다. IPv4 주소 고갈 문제를 상당 부분 완화시킨 기술입니다.
실전 팁
💡 - 집에서 ifconfig나 ipconfig를 실행하면 보통 사설 IP(192.168.x.x)가 나옵니다
- 공인 IP를 확인하려면 whatismyip.com 같은 사이트를 이용하세요
- NAT 환경에서는 외부에서 내부로 먼저 연결을 시작하기 어렵습니다 (포트 포워딩 필요)
5. NAPT Network Address Port Translation
김개발 씨가 NAT에 대해 더 알아보니 "PAT", "NAPT", "IP Masquerading" 같은 용어들이 나왔습니다. 다 비슷해 보이는데 무슨 차이가 있는 걸까요?
**NAPT(Network Address Port Translation)**은 IP 주소뿐만 아니라 포트 번호까지 함께 변환하는 NAT의 확장입니다. 가정용 공유기에서 사용하는 NAT은 대부분 NAPT입니다.
PAT(Port Address Translation)이라고도 부릅니다.
다음 코드를 살펴봅시다.
# NAPT 동작 상세 시뮬레이션
class NAPT:
def __init__(self, public_ip):
self.public_ip = public_ip
self.nat_table = {}
self.port_pool = list(range(40000, 60000))
def process_outbound(self, src_ip, src_port, dst_ip, dst_port):
# 동일한 연결이면 기존 매핑 재사용
connection = (src_ip, src_port, dst_ip, dst_port)
if connection in self.nat_table:
return self.nat_table[connection]
# 새 포트 할당
new_port = self.port_pool.pop(0)
self.nat_table[connection] = new_port
print(f"NAPT 매핑 생성:")
print(f" 내부: {src_ip}:{src_port} -> 외부: {self.public_ip}:{new_port}")
print(f" 목적지: {dst_ip}:{dst_port}")
return new_port
def process_inbound(self, dst_port, src_ip, src_port):
# 역방향 조회
for conn, nat_port in self.nat_table.items():
if nat_port == dst_port and conn[2] == src_ip:
return conn[0], conn[1] # 원래 내부 IP, 포트
return None
박시니어 씨가 화이트보드에 표를 그리기 시작했습니다. "NAT에도 여러 종류가 있어.
가장 기본적인 건 정적 NAT인데, 이건 사설 IP 하나에 공인 IP 하나를 1:1로 매핑하는 거야." "그럼 공인 IP가 기기 수만큼 필요하겠네요?" 김개발 씨가 물었습니다. "맞아.
그래서 잘 안 써. 대신 우리가 쓰는 건 NAPT야." **NAPT(Network Address Port Translation)**은 하나의 공인 IP를 여러 사설 IP가 공유할 수 있게 해주는 기술입니다.
핵심은 포트 번호를 활용하는 것입니다. 정적 NAT이 "아파트 동 전체를 빌리는 것"이라면, NAPT은 "아파트 한 동에서 여러 호실을 나눠 쓰는 것"과 같습니다.
공인 IP가 동 주소라면, 포트 번호가 호실 번호입니다. NAPT의 동작 원리를 자세히 살펴보겠습니다.
내부 기기 A(192.168.1.10:50000)가 외부 서버에 연결을 시도합니다. NAPT 장비는 이 연결에 새 포트(예: 40001)를 할당하고, 출발지를 공인IP:40001로 변환합니다.
동시에 기기 B(192.168.1.20:50000)도 연결을 시도합니다. 같은 내부 포트(50000)를 쓰고 있지만, NAPT는 다른 외부 포트(40002)를 할당합니다.
이렇게 포트 번호로 각 연결을 구분합니다. NAPT은 PAT(Port Address Translation), IP Masquerading, 네트워크 마스커레이딩 등 다양한 이름으로 불립니다.
Linux에서 iptables로 설정하는 NAT도 대부분 NAPT입니다. NAPT의 장점은 명확합니다.
공인 IP 하나로 이론상 약 6만 개의 동시 연결을 처리할 수 있습니다(포트 범위가 약 6만 개이므로). 실제로는 다양한 제약이 있지만, 가정이나 소규모 사무실에서는 충분합니다.
하지만 NAPT에도 단점이 있습니다. 외부에서 내부로 먼저 연결을 시작하기 어렵습니다.
NAPT 테이블에 매핑이 없으면, 들어오는 패킷을 어디로 보내야 할지 알 수 없기 때문입니다. 이 문제를 해결하는 것이 바로 포트 포워딩입니다.
또한 일부 프로토콜은 NAPT와 호환되지 않습니다. FTP의 액티브 모드나 일부 VoIP 프로토콜은 패킷 내부에 IP 주소를 포함하고 있어서, 단순히 헤더만 변환하는 NAPT로는 제대로 동작하지 않습니다.
이런 경우를 위해 **ALG(Application Layer Gateway)**라는 추가 기술이 필요합니다. 위의 코드는 NAPT의 핵심 로직을 보여줍니다.
process_outbound가 나가는 패킷을 처리하고, process_inbound가 들어오는 패킷을 원래 기기로 전달합니다. 4-튜플(출발지 IP, 출발지 포트, 목적지 IP, 목적지 포트)로 각 연결을 고유하게 식별합니다.
실전 팁
💡 - 대부분의 가정용 공유기는 NAPT을 사용합니다
- 공인 IP당 약 6만 개의 동시 연결이 가능합니다
- P2P 통신이나 게임 서버 호스팅에는 포트 포워딩이 필요할 수 있습니다
6. 포트 포워딩 개념
김개발 씨가 집에서 개인 서버를 운영하려고 합니다. 그런데 공유기 뒤에 있어서 외부에서 접속이 안 됩니다.
"포트 포워딩을 설정해야 해"라는 말을 들었는데, 정확히 무엇을 어떻게 해야 하는 걸까요?
**포트 포워딩(Port Forwarding)**은 공유기의 특정 포트로 들어오는 연결을 내부 네트워크의 특정 기기로 전달하는 설정입니다. NAT 환경에서 외부로부터의 인바운드 연결을 가능하게 해주는 필수 기술입니다.
다음 코드를 살펴봅시다.
# 포트 포워딩 설정 시뮬레이션
class PortForwarding:
def __init__(self, public_ip):
self.public_ip = public_ip
self.forward_rules = {}
def add_rule(self, external_port, internal_ip, internal_port, protocol="TCP"):
self.forward_rules[external_port] = {
"internal_ip": internal_ip,
"internal_port": internal_port,
"protocol": protocol
}
print(f"포트 포워딩 규칙 추가:")
print(f" {self.public_ip}:{external_port} -> {internal_ip}:{internal_port} ({protocol})")
def process_incoming(self, dst_port, protocol="TCP"):
if dst_port in self.forward_rules:
rule = self.forward_rules[dst_port]
if rule["protocol"] == protocol:
print(f"포워딩: 포트 {dst_port} -> {rule['internal_ip']}:{rule['internal_port']}")
return rule["internal_ip"], rule["internal_port"]
print(f"포트 {dst_port}에 대한 포워딩 규칙 없음 - 패킷 드롭")
return None
# 사용 예시
router = PortForwarding("211.100.50.30")
router.add_rule(80, "192.168.1.100", 80) # 웹 서버
router.add_rule(22, "192.168.1.100", 22) # SSH
router.add_rule(25565, "192.168.1.50", 25565) # 마인크래프트 서버
김개발 씨는 집에서 토이 프로젝트용 서버를 운영하고 싶었습니다. 라즈베리 파이에 웹 서버를 설치하고 실행까지 했습니다.
그런데 외부에서 접속하려니까 연결이 되지 않습니다. "왜 안 되는 거지?" 김개발 씨는 공유기 설정 화면을 열어봤습니다.
이유는 간단합니다. NAT 환경에서는 외부에서 먼저 연결을 시작할 수 없습니다. 내부에서 외부로 나가는 연결은 NAT 테이블에 기록되므로 응답이 돌아올 수 있습니다.
하지만 외부에서 갑자기 들어오는 연결은 매핑 정보가 없어서 어디로 보내야 할지 알 수 없습니다. 이 문제를 해결하는 것이 포트 포워딩입니다.
포트 포워딩은 "공유기의 특정 포트로 들어오는 연결은 내부의 특정 기기로 보내라"는 규칙을 미리 설정해두는 것입니다. 비유를 들어보겠습니다.
회사 대표번호로 전화가 오면 교환원이 "1번을 누르면 영업팀, 2번을 누르면 기술팀"이라고 안내합니다. 포트 포워딩도 마찬가지입니다.
"80번 포트로 오면 웹 서버, 22번 포트로 오면 SSH 서버"처럼 미리 경로를 지정해두는 것입니다. 김개발 씨의 경우, 공유기 설정에서 다음과 같이 설정하면 됩니다.
외부 포트 80을 내부 IP 192.168.1.100의 포트 80으로 포워딩합니다. 이제 외부에서 공인 IP의 80번 포트로 접속하면, 공유기가 자동으로 라즈베리 파이로 연결을 전달합니다.
포트 포워딩 설정 시 주의할 점이 있습니다. 첫째, 내부 기기의 IP가 바뀌면 안 됩니다. DHCP를 사용하면 IP가 바뀔 수 있으므로, 서버에는 고정 IP를 할당하거나 DHCP 예약을 설정해야 합니다.
둘째, 보안에 주의해야 합니다. 포트 포워딩은 외부에서 내부 네트워크로 들어오는 문을 여는 것입니다. SSH 서버를 노출하면 무차별 대입 공격의 대상이 될 수 있습니다.
강력한 비밀번호를 사용하거나, 키 기반 인증을 설정하세요. 셋째, ISP가 포트를 차단하는 경우도 있습니다. 일부 인터넷 서비스 제공자는 80번 같은 Well-known 포트를 차단합니다.
이 경우 8080 같은 대체 포트를 사용해야 합니다. 위의 코드는 포트 포워딩의 동작을 시뮬레이션합니다.
add_rule로 규칙을 추가하고, process_incoming으로 들어오는 패킷을 처리합니다. 실제 공유기에서는 웹 인터페이스를 통해 비슷한 설정을 할 수 있습니다.
마인크래프트 서버, 개인 블로그, 홈 CCTV 등을 외부에서 접속하려면 포트 포워딩이 필수입니다. 네트워크를 이해하는 개발자라면 반드시 알아야 할 기술입니다.
실전 팁
💡 - 서버에는 고정 IP 또는 DHCP 예약을 설정하세요
- 보안을 위해 가능하면 비표준 포트를 사용하세요 (22 대신 2222 등)
- 공유기 모델마다 설정 방법이 다르니 매뉴얼을 참고하세요
7. ICMP 프로토콜 이해
김개발 씨가 서버 연결이 안 될 때 가장 먼저 하는 일은 ping 명령어를 치는 것입니다. "Ping이 가면 네트워크는 문제없는 거야"라고 들었는데, ping은 정확히 어떤 원리로 동작하는 걸까요?
**ICMP(Internet Control Message Protocol)**는 네트워크 장비 간에 오류 메시지와 운영 정보를 교환하는 프로토콜입니다. ping과 traceroute 명령어가 ICMP를 사용하며, IP 프로토콜의 한계를 보완하는 보조 역할을 합니다.
다음 코드를 살펴봅시다.
import subprocess
import platform
def ping_host(host, count=4):
# 운영체제에 따라 ping 옵션이 다름
param = '-n' if platform.system().lower() == 'windows' else '-c'
command = ['ping', param, str(count), host]
try:
result = subprocess.run(command, capture_output=True, text=True, timeout=10)
if result.returncode == 0:
print(f"{host} 연결 성공!")
print(result.stdout)
return True
else:
print(f"{host} 연결 실패")
return False
except subprocess.TimeoutExpired:
print(f"{host} 응답 시간 초과")
return False
# ICMP 메시지 타입
ICMP_TYPES = {
0: "Echo Reply (ping 응답)",
3: "Destination Unreachable (목적지 도달 불가)",
8: "Echo Request (ping 요청)",
11: "Time Exceeded (TTL 초과 - traceroute에서 사용)",
}
서버가 응답하지 않을 때, 개발자들이 가장 먼저 하는 일이 있습니다. 바로 터미널을 열고 ping을 치는 것입니다.
"ping google.com" 엔터. 화면에 응답 시간이 출력됩니다.
"64 bytes from 142.250.199.110: icmp_seq=1 ttl=117 time=31.2 ms" "ping이 가니까 네트워크는 문제없어." 박시니어 씨가 말했습니다. 하지만 김개발 씨는 궁금했습니다.
ping은 도대체 어떻게 동작하는 걸까요? **ICMP(Internet Control Message Protocol)**는 IP 프로토콜과 함께 동작하는 보조 프로토콜입니다.
IP가 데이터를 전달하는 동안, ICMP는 "네트워크에 문제가 있다"거나 "목적지에 도달할 수 없다" 같은 제어 메시지를 전달합니다. IP 프로토콜은 "최선형(Best Effort)" 서비스입니다.
데이터가 손실되거나 도달하지 못해도 알려주지 않습니다. ICMP가 이 빈틈을 메웁니다.
패킷이 목적지에 도달하지 못하면, 중간 라우터가 ICMP 메시지로 이 사실을 알려줍니다. ping 명령어는 ICMP Echo Request와 Echo Reply를 사용합니다.
ping을 실행하면 Echo Request(타입 8) 메시지를 목적지로 보냅니다. 목적지가 살아있으면 Echo Reply(타입 0)로 응답합니다.
이 왕복 시간을 측정해서 네트워크 지연 시간을 알 수 있습니다. traceroute(Windows에서는 tracert) 명령어도 ICMP를 활용합니다.
이 명령어는 **TTL(Time To Live)**을 교묘하게 사용합니다. TTL은 패킷이 거칠 수 있는 라우터 수의 제한입니다.
라우터를 하나 지날 때마다 TTL이 1씩 줄어들고, 0이 되면 패킷은 폐기됩니다. traceroute는 TTL을 1부터 시작해서 하나씩 늘려가며 패킷을 보냅니다.
TTL이 1이면 첫 번째 라우터에서 폐기되고, 그 라우터가 Time Exceeded(타입 11) 메시지를 보냅니다. 이 메시지에는 라우터의 IP가 담겨 있습니다.
TTL을 2로 설정하면 두 번째 라우터의 정보를 얻을 수 있습니다. 이렇게 목적지까지의 경로를 추적합니다.
Destination Unreachable(타입 3)은 목적지에 도달할 수 없을 때 발생합니다. 네트워크가 없거나, 호스트가 다운되었거나, 포트가 열려있지 않을 때 이 메시지가 반환됩니다.
세부 코드로 정확한 이유를 알 수 있습니다. ICMP는 전송 계층 프로토콜(TCP, UDP)이 아닙니다.
네트워크 계층(IP)에서 동작합니다. 그래서 포트 번호가 없습니다.
방화벽에서 ICMP를 차단하면 ping이 동작하지 않습니다. 보안상 ICMP를 차단하는 서버도 많습니다.
"그럼 ping이 안 가면 서버가 다운된 건가요?" 김개발 씨가 물었습니다. "꼭 그런 건 아니야." 박시니어 씨가 대답했습니다.
"ICMP가 차단되어 있을 수도 있거든. 그래서 서버 상태를 확인할 때는 ping만 믿으면 안 돼.
실제 서비스 포트로 연결을 시도해보는 게 더 정확해." 네트워크 문제를 진단할 때 ICMP는 첫 번째 도구입니다. 하지만 한계도 있다는 것을 기억하세요.
실전 팁
💡 - ping이 안 된다고 서버가 다운된 게 아닙니다. ICMP 차단일 수 있습니다
- traceroute로 네트워크 경로와 병목 구간을 찾을 수 있습니다
- 서버 상태 확인에는 telnet이나 curl로 실제 포트 연결을 시도해보세요
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
Helm 마이크로서비스 패키징 완벽 가이드
Kubernetes 환경에서 마이크로서비스를 효율적으로 패키징하고 배포하는 Helm의 핵심 기능을 실무 중심으로 학습합니다. Chart 생성부터 릴리스 관리까지 체계적으로 다룹니다.
보안 아키텍처 구성 완벽 가이드
프로젝트의 보안을 처음부터 설계하는 방법을 배웁니다. AWS 환경에서 VPC부터 WAF, 암호화, 접근 제어까지 실무에서 바로 적용할 수 있는 보안 아키텍처를 단계별로 구성해봅니다.
AWS Organizations 완벽 가이드
여러 AWS 계정을 체계적으로 관리하고 통합 결제와 보안 정책을 적용하는 방법을 실무 스토리로 쉽게 배워봅니다. 초보 개발자도 바로 이해할 수 있는 친절한 설명과 실전 예제를 제공합니다.
AWS KMS 암호화 완벽 가이드
AWS KMS(Key Management Service)를 활용한 클라우드 데이터 암호화 방법을 초급 개발자를 위해 쉽게 설명합니다. CMK 생성부터 S3, EBS 암호화, 봉투 암호화까지 실무에 필요한 모든 내용을 담았습니다.
AWS Secrets Manager 완벽 가이드
AWS에서 데이터베이스 비밀번호, API 키 등 민감한 정보를 안전하게 관리하는 Secrets Manager의 핵심 개념과 실무 활용법을 배워봅니다. 초급 개발자도 쉽게 따라할 수 있도록 실전 예제와 함께 설명합니다.