포트
고친 사람 github-actions[bot]
포트는 컴퓨터에 도착한 데이터를 그 안의 어느 프로그램에게 건넬지 가리킵니다. 컴퓨터 한 대에서 프로그램 여럿이 동시에 통신할 수 있는 것이 포트 덕분입니다. 웹 서버가 443번을 맡는 식으로 데이터를 받는 프로그램이 번호를 맡습니다.
쉽고 빠른 이해
포트는 컴퓨터에 들어온 데이터를 어느 프로그램에게 줄지 정하는 번호입니다. 웹 서버가 443번을 맡고 있으면 443번으로 온 데이터는 그 웹 서버에게 갑니다.
번호가 없으면 받는 쪽은 데이터가 자기 컴퓨터로 온 것까지만 압니다. 그 안에서 도는 프로그램 여럿 중 누구에게 줄지는 모릅니다.
어떻게 도나:
- 받는 프로그램이 번호 하나를 맡겠다고 운영체제에 알립니다
- 거는 쪽은 상대 컴퓨터 주소와 그 번호를 함께 적어 보냅니다. 자기 번호는 운영체제가 빈 것을 골라 줍니다
- 받는 쪽 운영체제는 도착한 데이터의 번호를 보고 그 번호를 맡은 프로그램에게 넘깁니다
대가는 번호를 미리 맞춰 둬야 한다는 것입니다. 한 컴퓨터에서 같은 번호를 두 프로그램이 함께 맡는 일은 대개 안 됩니다. 중간 장비가 번호를 보고 막으면 서버가 떠 있어도 연결이 안 됩니다.
상세
아파트 단지로 오는 택배를 떠올리면 됩니다. 동 번호까지만 적힌 상자는 경비실에서 멈춥니다. 호수가 적혀 있어야 집 앞까지 갑니다.
포트는 한 컴퓨터 안에서 통신 상대 프로그램을 가리키는 번호입니다. 웹 서버가 443번을 맡고 있으면 443번으로 온 데이터는 그 웹 서버에게 갑니다.
IP(Internet Protocol, 인터넷 프로토콜) 주소는 어느 컴퓨터인지까지 알려 줍니다. 포트가 그 안의 어느 프로그램인지를 마저 짚습니다. 어느 번호를 어느 프로그램에 붙일지는 컴퓨터마다 스스로 정합니다.
포트가 하는 일은 둘입니다. 첫째는 같은 두 컴퓨터 사이를 오가는 통신 여럿을 서로 가르는 일입니다. 둘째로 접속하는 쪽이 어느 서비스에 붙으려는지를 알려 주기도 합니다.
헤더의 두 칸
번호는 데이터 앞에 붙는 정보 묶음인 헤더에 실려 갑니다. IP 헤더에는 보내는 컴퓨터와 받는 컴퓨터의 주소가 실립니다. 포트는 그 뒤에 붙는 전송 프로토콜의 헤더에 실립니다.
TCP(Transmission Control Protocol, 전송 제어 프로토콜)는 데이터가 빠짐없이 순서대로 닿게 챙기며 실어 나르는 프로토콜입니다. UDP(User Datagram Protocol, 사용자 데이터그램 프로토콜)는 그런 보장 없이 보내기만 합니다. 둘 다 헤더 맨 앞에 출발 포트 칸과 도착 포트 칸을 둡니다.
packet-beta 0-15: "출발 포트" 16-31: "도착 포트"
두 칸은 각각 16비트입니다. 16비트에 담을 수 있는 수는 65,536 개라서 번호는 0부터 65535까지입니다.
UDP 에서는 출발 포트를 안 적어도 됩니다. 안 쓰면 그 칸에 0을 넣습니다. 적혀 있으면 받는 쪽은 다른 정보가 없을 때 그 번호로 답장하면 된다고 여길 수 있습니다.
포트 번호는 전송 프로토콜마다 따로 셉니다. TCP 의 443번과 UDP 의 443번은 서로 다른 포트입니다.
TCP 와 UDP 뒤에 나온 전송 프로토콜도 포트를 같은 방식으로 씁니다. SCTP(Stream Control Transmission Protocol, 스트림 제어 전송 프로토콜)가 그렇습니다. DCCP(Datagram Congestion Control Protocol, 데이터그램 혼잡 제어 프로토콜)도 16비트 번호를 똑같이 씁니다.
주소와 포트의 분담
IP 주소는 인터넷에서 컴퓨터 한 대를 가리킵니다. 그런데 그 컴퓨터 안에서는 웹 서버와 이름 조회 서버와 원격 접속 서버가 같이 돕니다. 도착한 데이터를 누구에게 줄지는 주소만으로 못 정합니다.
누구에게 줄지는 포트가 정합니다. 운영체제는 도착한 데이터에서 도착 포트 번호를 읽습니다. 그 번호를 맡은 프로그램에게 데이터를 넘깁니다. 여러 프로그램의 통신을 주소 하나에 겹쳐 싣고 번호로 다시 가르는 이 방식을 다중화라고 합니다.
flowchart TD
P["도착한 데이터 · 도착 포트 443"] --> K
subgraph H["컴퓨터 한 대"]
K["운영체제 · 도착 포트를 읽는다"]
K -.->|"번호 안 맞음 · 안 감"| A["22번 · 원격 접속 서버"]
K -->|"번호 맞음"| B["443번 · 웹 서버"]
K -.->|"번호 안 맞음 · 안 감"| C["53번 · 이름 조회 서버"]
end
그림에서 데이터는 주소를 보고 컴퓨터까지 왔습니다. 그 안에서 갈래는 셋입니다. 데이터가 가는 길은 번호가 맞는 하나뿐입니다.
맡는 쪽과 빌리는 쪽
데이터를 받으려는 프로그램은 번호 하나를 맡겠다고 운영체제에 알립니다. 이 등록을 바인드라고 합니다. 그 뒤로 그 번호로 오는 연결을 기다립니다. 이렇게 기다리는 상태를 그 포트를 듣는다고 말합니다.
연결을 거는 쪽은 번호를 고르지 않아도 됩니다. 운영체제가 비어 있는 번호 하나를 골라 붙여 줍니다. 답장이 어느 프로그램의 것인지 가리려면 거는 쪽에도 번호가 있어야 해서입니다. 이렇게 그때그때 빌려 주는 번호를 임시 포트라고 부릅니다.
sequenceDiagram
participant A as 거는 프로그램
participant B as 거는 쪽 운영체제
participant C as 받는 쪽 운영체제
participant D as 받는 프로그램
D->>C: 443번을 맡겠다고 알린다 · 바인드
Note over C,D: 443번을 듣는다
A->>B: 상대 주소의 443번으로 연결을 건다
Note over B: 빈 번호 하나를 임시 포트로 골라 붙인다
B->>C: 출발 포트 = 임시 포트 · 도착 포트 = 443
C->>D: 443번을 맡은 프로그램에게 넘긴다
C-->>B: 답장 · 도착 포트 = 임시 포트
B-->>A: 임시 포트를 붙인 프로그램에게 넘긴다
그림에는 번호가 둘 나옵니다. 443번은 받는 프로그램이 스스로 맡았습니다. 임시 포트는 거는 쪽 운영체제가 골랐습니다.
한 컴퓨터에서 같은 서비스를 둘 띄워도 같은 번호를 함께 듣는 일은 대개 안 됩니다. 이미 맡힌 번호를 또 맡으려 할 때 돌아오는 값은 아래 실패 절에 있습니다.
번호의 세 구간
번호마다 어느 서비스가 쓰는지를 적어 두는 등록부가 있습니다. IANA(Internet Assigned Numbers Authority, 인터넷 할당 번호 관리 기관)가 이 등록부에 번호를 기록합니다.
등록부는 번호 전체를 세 구간으로 나눕니다. 구간마다 이름이 둘씩 있습니다.
| 구간 | 이름 | 다른 이름 | 등록부의 배정 |
|---|---|---|---|
| 0 ~ 1023 | 시스템 포트 | 잘 알려진 포트 | IANA 가 배정합니다 |
| 1024 ~ 49151 | 사용자 포트 | 등록 포트 | IANA 가 배정합니다 |
| 49152 ~ 65535 | 동적 포트 | 사설 포트 · 임시 포트 | 배정하지 않습니다 |
이 구간은 등록부가 번호를 나눠 주는 규칙입니다. 어느 번호에서 무엇을 들을지는 연결 양 끝이 정할 일입니다. 많은 서비스에는 서버가 할 수 있으면 대개 듣는 기본 번호가 하나 있습니다. 등록부에 오르는 것이 그 기본 번호입니다.
번호 하나가 꼭 서비스 하나를 뜻한다는 가정은 시간이 갈수록 덜 맞게 될 수 있습니다. 같은 서비스를 늘 같은 번호에 둘 수는 없어서입니다. 한 컴퓨터에서 같은 서비스를 둘 띄우면 대개 같은 번호를 함께 듣지 못합니다. 주소를 바꿔 쓰는 장비 하나 뒤에 놓인 컴퓨터 여럿도 바깥쪽의 같은 번호를 모두 가질 수는 없습니다.
운영체제가 빌려 주는 임시 포트 범위도 이 표의 동적 포트 구간과 다를 수 있습니다. 두 범위의 값은 실패 절에서 견줍니다.
같은 번호로 여러 연결 받기
웹 서버는 443번 하나로 수천 개의 연결을 동시에 받습니다. 번호는 하나뿐입니다. 그래도 연결끼리 섞이지 않습니다. 연결 하나를 가리키는 것이 도착 포트 하나가 아니라 네 값의 묶음이기 때문입니다.
아래 표가 그 네 값입니다. 같은 443번에 붙은 연결 셋이 각각 어떤 값을 갖는지 옆에 적었습니다.
| 값 | 무엇이 들어가나 | 연결 1 | 연결 2 | 연결 3 |
|---|---|---|---|---|
| 출발지 주소 | 걸어온 컴퓨터의 주소 | 10.0.0.5 | 10.0.0.5 | 198.51.100.7 |
| 출발 포트 | 걸어온 쪽이 빌려 쓴 번호 | 51413 | 51414 | 40002 |
| 도착지 주소 | 서버 컴퓨터의 주소 | 203.0.113.9 | 203.0.113.9 | 203.0.113.9 |
| 도착 포트 | 서버가 맡고 있는 번호 | 443 | 443 | 443 |
같은 서버에 붙은 두 클라이언트는 출발지 주소가 다릅니다. 한 클라이언트가 연결을 둘 열어도 출발 포트가 서로 다릅니다. 그래서 네 값을 묶으면 연결마다 값이 달라집니다.
주소에 포트를 이어 붙인 것을 소켓이라고 부릅니다. 연결 하나는 양 끝의 소켓 한 쌍으로 가려집니다. 서버 쪽 소켓 하나는 여러 연결에 동시에 쓰일 수 있습니다.
포트를 읽는 중간 장비
포트 번호는 양 끝의 컴퓨터만 읽는 것이 아닙니다. 그 사이에서 데이터를 걸러 내거나 고쳐 쓰는 장비도 읽습니다. 이 소절은 그런 장비 둘을 봅니다.
방화벽은 도착 포트를 보고 어느 서비스로 가는 데이터인지 가늠합니다. 그 판단으로 통과와 차단을 가릅니다. 서버가 멀쩡히 떠 있어도 방화벽이 그 번호를 막으면 밖에서 붙지 못합니다.
NAT(Network Address Translation, 네트워크 주소 변환)는 나가는 데이터의 주소와 출발 포트를 바꿔 씁니다. 바꾼 짝은 적어 둡니다. 답장이 돌아오면 그 짝을 보고 원래 컴퓨터에게 돌려줍니다. 한 왕복은 예시 절에 그렸습니다.
배경
컴퓨터 한 대에서는 프로그램 여럿이 동시에 통신합니다. 그런데 IP 헤더가 싣는 것은 보내는 컴퓨터와 받는 컴퓨터의 주소입니다. 주소만 보고는 도착한 데이터를 그 안의 어느 프로그램에게 건넬지 정하지 못합니다.
그래서 전송 프로토콜이 컴퓨터마다 주소 묶음을 하나 더 두었습니다. 그 묶음 안의 번호가 포트입니다. 컴퓨터 주소에 포트를 이어 붙이면 소켓이 됩니다. 소켓 한 쌍이 연결 하나를 가립니다.
번호를 두는 것만으로는 모자랐습니다. 처음 접속하는 쪽이 상대 프로그램의 번호를 미리 알아야 합니다. 그래서 자주 찾는 서비스는 번호를 정해 널리 알렸습니다. 서버와 접속하는 쪽과 중간 장비가 번호와 서비스의 짝을 같게 알아야 합니다. 그 짝을 등록부에 적어 두는 까닭입니다.
예시
포트 번호가 적혀 나오는 곳 다섯을 봅니다. 등록부 · 웹 주소 · 운영체제 설정 파일 · 컨테이너 설정 · 공유기입니다. 같은 16비트 번호가 곳마다 어떤 꼴로 나타나는지가 이 절의 관심입니다.
IANA 서비스 이름 · 포트 번호 등록부
등록부에서 몇 줄을 옮겼습니다. 열은 열둘입니다. 앞 넷만 남겼습니다.
Service Name,Port Number,Transport Protocol,Description
ssh,22,tcp,The Secure Shell (SSH) Protocol
domain,53,tcp,Domain Name Server
domain,53,udp,Domain Name Server
https,443,tcp,http protocol over TLS/SSL
https,443,udp,http protocol over TLS/SSL
https,443,sctp,HTTPS
한 줄이 서비스 이름 하나 · 번호 하나 · 전송 프로토콜 하나의 짝입니다. 이름 조회 서버인 domain 은 53번에 tcp 와 udp 로 한 줄씩 올라 있습니다. 포트 번호를 전송 프로토콜마다 따로 세서 같은 번호를 두 번 적습니다. https 의 443번은 tcp · udp · sctp 세 줄입니다.
URL 의 포트
URL(Uniform Resource Locator)에서는 호스트 이름 뒤에 콜론 하나를 찍고 십진수로 포트를 적습니다. 주소 맨 앞의 http · https 같은 부분은 스킴이라고 부릅니다. 스킴마다 기본 포트를 정해 둘 수 있어서 포트는 생략할 수 있습니다.
http 스킴의 기본 포트는 TCP 80번입니다. 그래서 http 주소에 :80 을 붙이면 기본값을 다시 적은 것이 됩니다. URL 을 만들거나 정규화하는 쪽은 이럴 때 :80 을 빼도록 권장됩니다. 포트가 TCP 번호인지 UDP 번호인지도 스킴이 정합니다.
운영체제의 services 파일
리눅스는 서비스 이름과 번호의 짝을 텍스트 파일 하나에 적어 둡니다. 경로는 대개 /etc/services 입니다. 네트워크 프로그램은 서비스의 번호를 이 파일에서 찾도록 권장됩니다.
chargen 19/tcp ttytst source
ftp 21/tcp
telnet 23/tcp
한 줄의 꼴은 서비스 이름 번호/프로토콜 [별칭 …] 입니다. 첫째 줄의 ttytst 와 source 가 chargen 의 별칭입니다.
도커의 -p 8080:80
컨테이너 안 프로그램이 맡은 번호를 바깥에 여는 설정입니다. docker run -p 8080:80 은 도커 호스트의 8080번과 컨테이너의 TCP 80번을 짝짓습니다. 호스트의 어느 주소로 온 8080번이든 컨테이너 80번으로 갑니다.
| 값 | 뜻 |
|---|---|
-p 8080:80 |
호스트 8080번 → 컨테이너 TCP 80번 |
-p 192.168.1.100:8080:80 |
호스트 주소 192.168.1.100 의 8080번만 → 컨테이너 TCP 80번 |
-p 8080:80/udp |
호스트 8080번 → 컨테이너 UDP 80번 |
공개하지 않은 포트로 오는 접근은 도커가 기본으로 막습니다. 짝짓기는 방화벽 규칙으로 합니다. 그 규칙이 주소와 포트를 바꿔 씁니다. 상세에서 본 NAT 와 같은 주소 변환입니다.
공유기의 NAT
안쪽 컴퓨터가 바깥으로 통신을 시작하면 NAT 는 그 통신에 바깥 주소와 포트를 하나 내줍니다. 이 짝을 주소 · 포트 매핑이라고 부릅니다. 답장이 돌아오면 이 짝으로 번역해 안쪽 컴퓨터에게 넘깁니다.
sequenceDiagram
participant 안쪽 as 안쪽 컴퓨터
participant 공유기
participant 바깥 as 바깥 서버
안쪽->>공유기: 안쪽 주소 · 안쪽 포트에서 보낸다
Note over 공유기: 안쪽 주소 · 포트 ↔ 바깥 주소 · 포트 짝을 만든다
공유기->>바깥: 바깥 주소 · 바깥 포트로 바꿔 보낸다
바깥-->>공유기: 바깥 주소 · 바깥 포트로 답한다
공유기-->>안쪽: 짝을 보고 안쪽 주소 · 안쪽 포트로 돌려준다
짝은 그 통신이 이어지는 동안 유지됩니다. 어떤 NAT 는 바깥 포트를 안쪽 포트와 같은 번호로 맞추려 합니다. 이 동작을 포트 보존이라고 부릅니다.
실패
포트 때문에 깨지는 경우를 리눅스 시스템 호출과 두 전송 프로토콜에서 봅니다. 조건마다 돌려받는 값이 다릅니다. 그 값을 보게 되는 쪽도 다릅니다.
| 조건 | 돌려받는 값 | 보는 쪽 |
|---|---|---|
이미 쓰이는 주소 · 포트를 bind 로 맡으려 함 |
bind 가 EADDRINUSE |
맡는 쪽 |
| 보호된 번호를 슈퍼유저가 아닌 프로세스가 맡으려 함 | bind 가 EACCES |
맡는 쪽 |
bind 에 포트 번호 0을 줌 · 임시 포트 범위가 전부 쓰이는 중 |
bind 가 EADDRINUSE |
임시 포트를 받으려던 쪽 |
bind 로 번호를 맡지 않은 채 connect 를 부름 · 임시 포트 범위가 전부 쓰이는 중 |
connect 가 EADDRNOTAVAIL |
거는 쪽 |
| TCP 로 걸음 · 그 포트를 듣는 쪽이 없음 | 상대가 리셋 신호 RST(Reset)를 보냄 · connect 는 ECONNREFUSED |
거는 쪽 |
| UDP 데이터가 듣는 쪽 없는 포트에 도착 | 받는 쪽 UDP 가 ICMP(Internet Control Message Protocol, 인터넷 제어 메시지 프로토콜) 포트 도달 불가 메시지를 보내도록 권장됨 | 보낸 쪽 |
둘째 줄의 보호된 번호는 1024 아래입니다. 이 번호를 특권 포트라고 부릅니다. 리눅스에서는 CAP_NET_BIND_SERVICE 능력(capability)이 있는 프로세스만 맡을 수 있습니다. 문턱 1024 는 ip_unprivileged_port_start 설정의 기본값입니다.
셋째 줄의 포트 0은 UDP 헤더의 출발 포트 칸에 넣는 0과 뜻이 다릅니다. bind 에 포트 번호를 0으로 주면 운영체제가 임시 포트 범위에서 빈 번호 하나를 골라 붙여 줍니다. 넷째 줄처럼 번호를 맡지 않은 채 connect 를 불러도 임시 포트를 붙여 줍니다.
셋째와 넷째 줄이 임시 포트가 다 찬 경우입니다. 이 상황을 포트 고갈이라고 부릅니다. 오류 값은 같은 고갈이어도 호출마다 다릅니다.
listen 과 sendto 도 번호를 맡기 전에 부르면 임시 포트를 붙여 받습니다. 그래서 이 두 호출에서도 고갈이 날 수 있습니다.
여섯째 줄의 포트 도달 불가는 ICMP 메시지의 한 종류입니다. ICMP 메시지 머리에는 사유를 가리는 코드 칸이 있습니다. 포트 도달 불가의 코드 값은 3입니다.
고갈의 문턱은 등록부의 동적 포트 구간 49152~65535 가 아닙니다. 운영체제가 정한 범위입니다. 리눅스는 /proc/sys/net/ipv4/ip_local_port_range 의 두 수로 이 범위를 정합니다. 기본값은 32768 과 60999 입니다.
경계
포트라는 낱말은 네트워크 밖에서도 쓰입니다. 이 절은 헷갈리는 사례 하나를 판정합니다. 그다음 이 표제어에 안 드는 포트를 가릅니다.
ping 의 포트 번호
ping 은 몇 번 포트를 쓸까요. 쓰지 않습니다.
ping 은 ICMP 에코 요청을 보내고 에코 응답을 받습니다. 에코 메시지의 머리에는 포트 칸이 없습니다.
packet-beta 0-7: "타입" 8-15: "코드" 16-31: "체크섬" 32-47: "식별자" 48-63: "순서 번호"
타입이 8이면 에코 요청입니다. 0이면 에코 응답입니다. 요청과 응답의 짝은 식별자 칸이 맞추도록 돕습니다. 이 칸은 0이어도 됩니다.
IP 자체에도 포트라는 개념이 없습니다. 포트는 TCP 와 UDP 같은, IP 위의 전송 프로토콜이 만듭니다. 그래서 ping 을 두고 포트 번호를 찾으면 답이 없습니다.
이름만 같은 포트
아래 넷은 이 표제어에 안 듭니다.
| 부르는 말 | 가리키는 것 | 네트워크 포트 번호인가 |
|---|---|---|
| 하드웨어 포트 | 케이블을 꽂는 물리 접점. USB(Universal Serial Bus, 범용 직렬 버스) 구멍 · 랜 케이블 구멍 | 아님 |
| 프로세서의 입출력 포트 | 프로세서가 주변 장치와 데이터를 주고받는 주소 | 아님. 번호지만 네트워크와 무관 |
| 헥사고날 아키텍처의 포트 | 애플리케이션이 바깥과 나누는 목적 있는 대화 하나 | 아님 |
| 포팅 | 소프트웨어를 다른 환경으로 옮기는 일 | 아님 |
프로세서의 입출력 포트가 제일 헷갈립니다. 인텔 x86 계열 프로세서는 8비트 입출력 포트를 65,536 개까지 둡니다. 번호는 0부터 FFFFH 까지라 개수가 네트워크 포트와 같습니다. 그래도 프로세서가 주변 장치와 데이터를 주고받는 번호라 네트워크 포트가 아닙니다.
헥사고날 아키텍처의 포트는 번호가 아니라 인터페이스입니다. 포트 하나가 애플리케이션과 바깥 사이의 목적 있는 대화 하나를 가리킵니다. 그 대화의 규칙이 API(Application Programming Interface, 애플리케이션 프로그래밍 인터페이스) 꼴을 띱니다. 네트워크 포트 번호는 가리키지 않습니다.
관련 항목
포트와 함께 목적지를 짚는 이름
IP 주소 · 소켓 · 호스트 · 도메인 · URL · 엔드포인트 · 스킴
포트 번호가 나뉘는 구간
잘 알려진 포트 · 등록 포트 · 임시 포트 · 특권 포트
포트를 헤더에 싣는 프로토콜
TCP · UDP · QUIC · SCTP · DCCP · 전송 계층 · 헤더 · 다중화
포트를 미리 약속해 둔 서비스
HTTP · HTTPS · DNS · SSH · SMTP · NTP
포트를 맡고 넘기는 프로그래밍 인터페이스
버클리 소켓 · bind · listen · accept · connect · 파일 디스크립터
포트 번호를 바꾸거나 걸러 내는 장비
NAT · 방화벽 · 포트 포워딩 · 프록시 · 로드 밸런서 · 라우터 · Docker
포트에서 비롯되는 장애와 공격
포트 고갈 · 포트 스캔 · 포트 도달 불가 · 연결 거부 · TIME_WAIT · EADDRINUSE · ECONNREFUSED · EACCES
포트 번호를 배정하고 등록하는 기관과 문서
IANA · RFC 6335 · 서비스 이름
포트 칸이 없는 프로토콜과 도구
포트라는 이름을 다른 뜻으로 쓰는 분야
하드웨어 포트 · 직렬 포트 · USB · 포팅 · 포트 입출력 · 포트 권한 · 헥사고날
다른 이름: port · ports · 포트 번호 · port number