sungyup's.

Web_Miscellaneous / 기초 개념 / 1.6 포트

1.6포트

네트워크 통신의 논리적 출입구, 포트

TL;DR

추억의 쪽지 시험

포트(Port)의 정의와 개념

포트는 네트워크 통신에서 논리적인 출입구 역할을 하는 번호이다. 네트워크 통신을 위해선 우선 통신하고자 하는 컴퓨터인 호스트를 알아야하는데, 그 컴퓨터 안에서 어떤 프로세스/서비스와 통신할지를 추가적으로 알아야 해당 컴퓨터의 해당 특정 프로그램과 연결이 가능하다. 이 추가적인 정보가 포트 번호로, 0번 ~ 65535번(16비트)으로 구성된다.

참고로 호스트 정보(IP 주소) + 포트 번호 = 소켓(Socket)이라고 한다.

포트가 필요한 이유는 멀티 프로세싱을 하기 위해서이다. 하나의 컴퓨터에서 웹 브라우저를 띄우고 메신저, 온라인 게임등 여러가지 네트워크 응용 프로그램을 실행하고 있을 때, 그 컴퓨터는 하나의 IP를 부여받으므로 웹사이트 서버, 메신저 서버 및 게임 서버와는 하나의 IP로 통신할 것이다. 따라서 웹사이트 서버, 메신저 서버 및 게임 서버 등 여러 서버가 보내주는 응답 패킷을 어떤 프로그램으로 보내야하는지 구분하는 식별자가 필요한데, 이 때 포트 번호가 쓰인다.

좀 더 구체적으로는, 클라이언트의 운영체제(OS)가 소켓 API(bind(), listen())를 통해 포트를 열고, 해당 포트를 특정 프로세스(여기선 웹 브라우저, 메신저, 온라인 게임)와 연결한다. 서버는 이미 포트를 열어두고(listen상태) 대기 중이다가, 클라이언트가 연결을 시도하면 커널이 연결을 맺어주고, 이로써 통신 채널이 만들어진다.

포트 번호 구간

  • Well-known Ports(0~1023)
    • OS가 특정 서비스에 할당해둔 번호로, 국제 도메인 관리기구에서 통제한다.
    • 예: 22(SSH), 53(DNS), 67(DHCP), 80(HTTP), 443(HTTPS)
  • Registered Ports(1024~49151)
    • 특정 애플리케이션/벤더가 요청해 등록할 수 있는 포트로, 국제 도메인 관리기구에 등록되어 있다.
    • 예: 3306(MySQL), 5432(PostgreSQL)
  • Dynamic/Private Ports(49152~65535)
    • 클라이언트가 서버에 접속할 때 임시로 사용하는 포트로, 운영체제가 자동으로 할당한다. 연결이 끊어지면 회수된다.
    • Ephemeral(일시적인) port라고도 부른다.

HTTPS 연결을 예로 들어보자. 서버는 443번 포트를 열어두고 기다린다. 클라이언트는 서버에 연결할 때 OS에서 프로세스에 할당한 Ephemeral Port를 열어 서버의 443번 포트와 연결을 맺는다. 이와 같은 상황을 확인하는 터미널 명령어 등에 대해선 다음 파트, 터미널 명령어 쪽에서 보다 자세히 알아보자.

포트와 관련된 터미널 명령어

웹/앱 개발을 하다보면 종종 여러가지 포트들을 쓰게 된다. 예를 들어, Next.js로 개발 시 next dev 명령어로 서버를 실행시키면 아래와 같은 메시지가 뜬다.

bash
> next dev
▲ Next.js 15.1.3
- Local: http://localhost:3000
- Network: http://192.168.1.201:3000
✓ Starting...
✓ Ready in 1456ms
○ Compiling / ...
✓ Compiled / in 1428ms (1499 modules)

참고로, http의 기본 포트는 80번이지만 웹 서버는 원한다면 다른 포트에서도 http 서비스를 열 수 있고 Next.js 개발 서버는 기본적으로 3000번 포트를 사용하기 때문에 :3000이 붙어있다. 여기서 Local에 있는 주소는 루프백 주소로, 지금 쓰고 있는 컴퓨터에서만 접근 가능한 주소이며 Network에 있는 주소는 컴퓨터의 사설 IP 주소로 같은 와이파이/랜에 연결된 다른 기기가 주소를 입력하면 개발 서버에 접속할 수 있다(즉, 내 컴퓨터를 네트워크를 통해 접근할 수 있는 방법으로 같은 네트워크 안 다른 기기에서 테스트할 수 있다).

lsof -i

가끔은 연결되어 있던 포트를 닫지 않고 다른 포트를 열거나 해서 헷갈릴 때가 있다. 이럴 때 포트가 어떻게 쓰이고 있는지를 보려면 lsof -i :<포트번호> 명령어를 쓸 수 있으며, 그냥 lsof -i를 쓰면 모든 네트워크 연결/리스닝 상태를 볼 수 있다.

참고로 lsof는 list open files의 약자인데 여기서 file은 유닉스 철학에서 말하는 파일로, 일반 디스크 파일뿐 아니라 소켓, 파이프, 장치 등 모든 입출력 자원이다. -i는 internet, 네트워크 관련 소켓을 대상으로만 출력하라는 의미이다.

bash
lsof -i :3000

위의 명령어를 방금 실행하니 아래와 같은 결과가 출력되었다.

port 3000
내 컴퓨터의 3000번 포트에서 실행되고 있는 인터넷 파일들

각 컬럼의 의미는 다음과 같다.

  1. COMMAND: 해당 파일(여기선 네트워크 소켓)을 연 프로세스의 실행 파일 이름. Google은 크롬 브라우저로 내 블로그 개발 상황을 띄워둬서 나온 것이고, nodenext dev로 열린 next.js 개발 서버이다.
  2. PID(Process ID): 프로세스 식별 번호로, 운영체제가 각 프로세스를 구분하기 위해 부여하는 고유 번호이다.
  3. USER: 프로세스를 실행한 사용자.
  4. FD(File Descriptor): 하나의 프로세스 내부에서 열린 파일/소켓을 식별하는 번호로, PID가 같은 경우 구별자로 쓰인다. 숫자 뒤에 붙는 글자는 접근 모드로, u는 읽기/쓰기, r은 읽기 전용(Read), w는 쓰기 전용(Write)이다.
  5. TYPE: 열린 파일의 유형으로, IPv4IPv6은 네트워크 소켓이라는 의미다.
  6. DEVICE: 커널 내부에서 장치를 식별하는 ID로, 사용자 입장에선 딱히 쓸 일이 없다.
  7. SIZE/OFF: 파일의 경우는 크기가 나오지만, 여기선 소켓만 있다보니 0t0으로 표시되었다.
  8. NODE: 네트워크 소켓에선 주로 TCPUDP가 표시된다. TCP와 UDP에 대한 보다 자세한 내용은 예전에 정리한 포스트를 참조.
  9. NAME: 실제 연결된 소켓의 상세 정보이다. 로컬주소:포트 -> 원격주소:포트 (상태) 식으로 표시된다.

위 이미지에서 나온 몇가지 예시들을 살펴보자.

  • localhost:61967 -> localhost:hbci (ESTABLISHED)
    • 내 PC(localhost)의 Ephemeral port 61967번이 내 PC(localhost)의 hbci라는 서비스(여기선 /etc/services 파일에 매핑된 서비스 이름으로, 실제론 3000번 포트다)에 연결되어 있고, 상태는 확립(ESTABLISHED)다.
  • *:hbci (LISTEN)
    • 3000번 포트를 모든 인터페이스(*)에서 수신 대기 중이라는 의미다.
  • localhost:hbci -> localhost:61967 (ESTABLISHED)
    • 아까 본 연결의 반대 연결로, 내 컴퓨터 브라우저에서 내 컴퓨터 서버로 연결한 상황(클라이언트이자 서버)이다 보니 그렇다.

kill -9 $(lsof -t -i :<포트번호>)

특정 포트의 프로세스를 종료하고 싶으면 kill -9라는 명령어를 쓴다. -9가 왜 붙는지 의아할 수 있는데, 사실 kill은 프로세스에 시그널을 보내는 명령어로 -9가 강제 종료 시그널이라서 -9가 붙어야 한다. -tlsof 출력에서 PID만 출력하는 옵션이다. 즉, 프로세스의 PID만 출력하게 해서 kill 명령어에 바로 넘겨줄 수 있도록 하는 옵션이다. $()는 이 안에 있는 명령어를 먼저 실행하고, 그 실행 결과를 바깥 명령어의 인자로 사용하라는 의미다.