netstat
고친 사람 github-actions[bot]
netstat 는 내 컴퓨터가 지금 어떤 네트워크 연결을 맺고 있는지 보여 주는 명령입니다. 어느 포트에서 접속을 기다리는지, 누구와 이어져 있는지를 한 줄씩 보여 줍니다. 서버에 안 붙거나 연결이 자꾸 쌓일 때 먼저 꺼내 보는 진단 명령입니다.
쉽고 빠른 이해
netstat 는 이 컴퓨터의 연결 목록을 보여 주는 명령입니다. netstat -tlnp 를 치면 「8080 번 포트를 java 프로세스가 기다리고 있다」 같은 줄이 찍힙니다.
연결은 운영체제 안에 있어서 눈에 안 보입니다. 이 명령이 없으면 「서버가 정말 떴나」, 「포트를 누가 잡고 있나」를 짐작으로 풀어야 합니다.
- 운영체제가 들고 있는 연결 목록을 읽어 옵니다
- 줄마다 내 주소, 상대 주소, 연결 상태를 적습니다
- 옵션으로 보고 싶은 줄만 걸러 냅니다
대가가 있습니다. 친 순간의 목록 한 장이라 잠깐 생겼다 사라진 연결은 놓칩니다. 오간 내용은 안 보입니다. 리눅스에서는 같은 일을 하는 새 명령 ss 로 옮겨 가는 중입니다.
상세
netstat 는 network statistics(네트워크 통계)를 줄인 이름입니다. 운영체제가 들고 있는 연결 목록과 몇 가지 네트워크 표를 사람이 읽을 모양으로 찍습니다. 리눅스, 맥, 윈도 모두 같은 이름의 명령을 갖고 있습니다.
백엔드 개발자가 이 명령을 꺼내는 때는 대개 셋입니다. 서버를 띄웠어도 밖에서 안 붙을 때입니다.
Address already in use(주소가 이미 쓰이는 중) 에러로 서버가 안 뜰 때입니다. 데이터베이스 연결이 몇 개나 열려 있는지 궁금할 때입니다.
세 경우 모두 답이 운영체제 안의 연결 목록에 있습니다. 이 목록은 눈으로 볼 방법이 따로 없어서 netstat 같은 명령으로 꺼내 봐야 합니다.
이 절은 먼저 연결 한 줄이 무엇을 담는지 봅니다. 그다음 출력을 읽는 법, 연결 상태, 옵션, 진단 장면을 차례로 봅니다.
소켓과 주소 한 쌍
프로그램이 네트워크로 말하려면 운영체제에 통로를 하나 달라고 청합니다. 그 통로를 소켓이라 부릅니다. 운영체제는 소켓마다 어떤 프로토콜을 쓰는지, 양 끝의 주소가 무엇인지 적어 둡니다. netstat 가 읽는 것이 이 기록입니다.
소켓의 주소는 IP 주소와 포트 번호의 한 쌍입니다. IP(Internet Protocol, 인터넷 프로토콜) 주소는 컴퓨터를 가리킵니다.
포트 번호는 그 컴퓨터 안의 프로그램을 가리킵니다. 10.0.0.5:5432 는 10.0.0.5 컴퓨터에서 5432 번 포트를 쓰는 프로그램입니다.
netstat 가 보여 주는 소켓은 주로 두 프로토콜의 것입니다. TCP(Transmission Control Protocol, 전송 제어 프로토콜)는 먼저 연결을 맺고 나서 데이터를 주고받습니다. UDP(User Datagram Protocol, 사용자 데이터그램 프로토콜)는 연결 없이 보내기만 합니다. 그래서 연결 상태는 TCP 소켓에만 찍힙니다.
서버 프로그램은 먼저 포트 하나를 정해 연결이 오기를 기다립니다. 이렇게 기다리기만 하는 소켓을 리슨 소켓이라 합니다.
서버에 연결을 청하는 쪽 프로그램은 클라이언트라 부릅니다. 클라이언트가 붙으면 운영체제는 그 클라이언트 몫의 소켓을 새로 만듭니다. 그래서 netstat 에는 기다리는 줄 하나와 클라이언트마다 이어진 줄이 따로 찍힙니다.
출력 한 줄을 읽는 법
리눅스에서 netstat -tan 으로 TCP 소켓을 전부 보면 아래 모양입니다. 옵션 글자의 뜻은 「자주 붙이는 옵션」 소절에서 풉니다. 주소는 예로 지어낸 것입니다.
$ netstat -tan
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN
tcp 0 0 10.0.0.5:8080 10.0.0.9:51724 ESTABLISHED
tcp 0 0 10.0.0.5:43120 10.0.0.7:5432 ESTABLISHED
tcp 0 0 10.0.0.5:8080 10.0.0.9:51690 TIME_WAIT
칸은 여섯입니다. 각 칸이 무엇인지는 아래 표와 같습니다.
| 칸 | 뜻 |
|---|---|
| Proto | 프로토콜. tcp · udp. IPv6(Internet Protocol version 6, 인터넷 프로토콜 6판) 소켓이면 tcp6 · udp6 |
| Recv-Q | 받았지만 프로그램이 아직 읽어 가지 않은 바이트 수 |
| Send-Q | 보냈지만 상대가 받았다고 아직 확인하지 않은 바이트 수 |
| Local Address | 이 컴퓨터 쪽 주소와 포트 |
| Foreign Address | 상대 쪽 주소와 포트 |
| State | TCP 연결 상태. 아래 소절에서 봅니다 |
첫 줄은 8080 번 포트의 리슨 소켓입니다. 아직 상대가 없어서 상대 주소가 0.0.0.0:* 로 비어 있습니다.
상대 칸의 이 값은 「상대가 없다」는 빈칸 표시일 뿐입니다. 같은 줄 내 칸의 0.0.0.0 은 뜻이 달라서 「0.0.0.0 과 127.0.0.1」 소절에서 따로 봅니다.
둘째 줄은 10.0.0.9 의 클라이언트가 이 컴퓨터의 8080 번에 붙은 연결입니다. 이 컴퓨터가 서버 쪽입니다.
셋째 줄은 방향이 반대입니다. 이 컴퓨터가 10.0.0.7 의 5432 번에 붙었습니다. 이 컴퓨터가 클라이언트 쪽입니다. 클라이언트 쪽 포트 43120 은 운영체제가 연결마다 비어 있는 번호를 골라 붙인 것입니다. 이런 포트를 임시 포트라 합니다.
누가 서버인지는 어느 쪽 포트가 늘 같은 번호인지로 가립니다. 서버는 정해 둔 번호로 기다립니다. 클라이언트는 연결마다 다른 임시 포트를 씁니다.
Recv-Q 와 Send-Q 는 평소 0 입니다. 잠깐 찼다가 비는 것은 정상입니다. Recv-Q 가 계속 차 있으면 프로그램이 읽는 속도가 들어오는 속도를 못 따라가는 것입니다. Send-Q 가 계속 차 있으면 프로그램이 보내는 속도를 상대나 그 사이의 망이 못 따라가는 것입니다.
0.0.0.0 과 127.0.0.1
컴퓨터가 망에 닿는 출입구 하나하나를 네트워크 인터페이스라 부릅니다. 유선 랜 카드와 와이파이가 각각 인터페이스 하나이고, 인터페이스마다 IP 주소가 따로 붙습니다.
리슨 소켓의 내 쪽 주소는 어느 인터페이스로 들어오는 연결을 받을지를 정합니다. 0.0.0.0 은 이 컴퓨터의 모든 인터페이스로 들어오는 연결을 받는다는 뜻입니다.
IPv6 소켓에서는 :: 가 같은 뜻입니다. 리눅스 netstat 는 이를 :::8080 으로 찍습니다.
127.0.0.1 은 루프백 주소입니다. 루프백은 컴퓨터가 자기 자신에게 보낼 때 쓰는 가상의 인터페이스입니다.
리슨 소켓이 127.0.0.1:8080 이면 같은 컴퓨터 안에서 온 연결만 받습니다. 다른 컴퓨터에서 오는 연결은 여기 닿지 못합니다.
이 차이가 「서버는 떴는데 밖에서 안 붙는다」의 흔한 원인입니다. 서버 설정에서 이 주소를 고르는 항목은 흔히 bind 나 host 라는 이름을 답니다. host 값을 127.0.0.1 로 둔 개발용 설정을 바꾸지 않고 올린 서버가 그렇습니다.
컨테이너 안에서 127.0.0.1 로 뜬 서버도 같습니다. 컨테이너 밖에서는 닿지 않습니다.
밖의 클라이언트를 받으려면 이 값을 0.0.0.0 이나 바깥 인터페이스의 주소로 바꿔 서버를 띄웁니다.
TCP 연결 상태
TCP 연결은 맺고 끊는 동안 여러 상태를 거칩니다. State 칸에 찍히는 것이 그 순간의 상태입니다. 백엔드에서 자주 보는 것은 아래 다섯입니다.
| 상태 | 뜻 | 많이 쌓이면 의심할 것 |
|---|---|---|
LISTEN |
리슨 소켓이 연결을 기다리는 중 | 쌓이지 않는다. 포트마다 하나 |
SYN_SENT |
연결을 청하고 답을 기다리는 중 | 상대가 죽었거나 방화벽이 막는다 |
ESTABLISHED |
연결이 맺어져 주고받는 중 | 연결을 안 닫는 코드가 있다 |
TIME_WAIT |
먼저 끊은 쪽이 잠시 기다리는 중 | 짧은 연결을 너무 자주 맺는다 |
CLOSE_WAIT |
상대가 끊은 뒤 내 프로그램이 아직 안 닫은 중 | 프로그램이 소켓을 안 닫는다 |
TIME_WAIT 와 CLOSE_WAIT 는 이름이 비슷해 헷갈립니다. 둘은 연결을 끊는 순서에서 서로 반대편에 생깁니다.
아래 그림은 한쪽이 먼저 끊을 때 양쪽에 어떤 상태가 남는지 보입니다.
sequenceDiagram
participant A as 먼저 끊는 쪽
participant B as 나중에 끊는 쪽
A->>B: 끊겠다는 신호
B-->>A: 받았다는 답
Note over B: CLOSE_WAIT · 내 프로그램이 닫기를 기다린다
B->>A: 나도 끊겠다는 신호
A-->>B: 받았다는 답
Note over A: TIME_WAIT · 잠시 기다렸다 사라진다
CLOSE_WAIT 는 상대의 끊는 신호를 받은 쪽에 생깁니다. 이 상태는 내 프로그램이 소켓을 닫아야 끝납니다.
운영체제는 프로그램 대신 닫아 주지 않습니다. 그래서 CLOSE_WAIT 가 계속 늘면 거의 늘 프로그램 쪽 버그입니다.
응답을 다 읽고도 응답 객체의 close() 를 부르지 않는 HTTP(HyperText Transfer Protocol, 하이퍼텍스트 전송 프로토콜) 클라이언트 코드가 대표적입니다.
TIME_WAIT 는 먼저 끊은 쪽에 생깁니다. 끊은 뒤에도 망 어딘가에 옛 연결의 패킷이 늦게 떠돌 수 있습니다. 같은 주소 한 쌍으로 새 연결을 곧바로 맺으면 그 늦은 패킷이 새 연결에 섞일 수 있습니다. 그래서 패킷이 망에 머물 수 있는 최대 시간의 두 배만큼 기다렸다가 사라집니다.
TIME_WAIT 는 정상 절차라 조금 있는 것은 문제가 아닙니다. 짧은 연결을 초마다 수없이 맺었다 끊는 쪽에서는 수가 크게 불어납니다.
이때는 연결을 매번 새로 맺지 말고 커넥션 풀로 돌려 씁니다.
자주 붙이는 옵션
netstat 는 옵션 글자로 볼 것을 고릅니다. 아래 표는 리눅스 기준입니다.
| 옵션 | 하는 일 |
|---|---|
-a |
리슨 소켓까지 전부 보인다. 없으면 맺어진 연결만 나온다 |
-t · -u |
TCP 소켓만 · UDP 소켓만 |
-l |
리슨 소켓만 |
-n |
주소와 포트를 이름으로 바꾸지 않고 번호로 찍는다 |
-p |
소켓을 쥔 프로세스의 번호와 이름을 붙인다 |
-n 이 없으면 netstat 는 주소마다 DNS(Domain Name System, 도메인 네임 시스템)에 이름을 물어봅니다. 포트 번호도 http 같은 서비스 이름으로 바꿉니다.
물어보는 데 시간이 걸리면 출력이 한참 멈춥니다. 그래서 진단할 때는 거의 늘 -n 을 붙입니다.
-p 는 PID(Process ID, 프로세스 번호)와 프로그램 이름을 4121/java 꼴로 붙입니다. 다른 사용자가 띄운 프로세스는 root 권한으로 쳐야 보입니다.
권한이 없으면 그 칸이 - 로만 찍힙니다.
글자는 여럿을 묶어 한 번에 씁니다. 가장 많이 치는 조합은 아래 둘입니다.
netstat -tlnp # 기다리는 TCP 포트와 주인
netstat -tanp # TCP 소켓 전부와 주인
운영체제마다 다른 옵션 글자
옵션 글자의 뜻은 운영체제마다 다릅니다. 같은 글자로 엉뚱한 결과가 나오면 이 차이부터 봅니다.
맥에서 -p 는 프로세스가 아니라 프로토콜을 고르는 옵션입니다. netstat -p tcp 꼴로 씁니다.
맥에서 포트를 쥔 프로세스를 찾을 때는 흔히 lsof(list open files, 열린 파일 목록)를 씁니다. lsof 는 프로세스가 연 파일과 소켓을 보여 주는 명령입니다.
윈도에서는 -o 가 PID 를 붙입니다. -b 는 실행 파일 이름을 붙입니다. 윈도에서 흔히 치는 조합은 netstat -ano 입니다.
연결 말고 보여 주는 표
netstat 는 연결 목록 말고도 표 셋을 더 보여 줍니다.
-r 은 라우팅 테이블을 보여 줍니다. 라우팅 테이블은 목적지 주소마다 패킷을 어느 인터페이스로 내보내고 다음에 어디로 넘길지 적은 표입니다.
패킷을 다른 망으로 넘겨주는 장비를 게이트웨이라 합니다. 목적지가 같은 망 안에 없으면 패킷은 라우팅 테이블에 적힌 게이트웨이로 먼저 갑니다.
목적지가 0.0.0.0 인 줄의 게이트웨이가 기본 게이트웨이입니다. 다른 줄에 안 맞는 패킷은 모두 이 줄을 따라 나갑니다.
-i 는 네트워크 인터페이스마다 주고받은 패킷 수를 찍습니다. 오류 수와 버린 패킷 수도 함께 나옵니다.
이 두 수가 계속 늘면 선, 네트워크 카드, 드라이버 쪽 문제를 의심합니다.
-s 는 프로토콜마다 쌓인 통계를 찍습니다. 컴퓨터가 켜진 뒤로 센 누적 값입니다.
TCP 항목의 재전송 수가 빠르게 늘면 망 어딘가에서 패킷이 사라지고 있다는 신호입니다. 누적 값이라 한 번 보다는 시간을 두고 두 번 찍어 차이를 봅니다.
진단 장면 셋
첫째는 서버가 Address already in use 에러를 내며 안 뜰 때입니다. 이 에러의 코드 이름은 EADDRINUSE 입니다.
같은 주소와 포트에는 대개 리슨 소켓을 하나만 열 수 있습니다. 그 포트를 누가 먼저 잡았는지 찾으면 됩니다.
$ netstat -tlnp | grep 8080
tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN 4121/java
맨 끝 칸이 포트를 잡은 프로세스입니다. 대개 전에 띄우고 안 끈 같은 서버입니다. 그 프로세스를 끄거나 포트를 바꿉니다.
둘째는 서버를 띄웠어도 다른 컴퓨터에서 안 붙을 때입니다. 먼저 서버 컴퓨터에서 리슨 소켓이 있는지 봅니다. 있으면 내 쪽 주소를 봅니다. 아래 그림이 그 순서입니다.
flowchart TD
A["밖에서 서버에 안 붙는다"] --> B{"netstat -tlnp 에 그 포트가 있나"}
B -->|"없다"| C["서버가 안 떴거나 다른 포트로 떴다"]
B -->|"있다"| D{"내 쪽 주소가 127.0.0.1 인가"}
D -->|"그렇다"| E["같은 컴퓨터 안의 연결만 받는다 · 0.0.0.0 으로 다시 띄운다"]
D -->|"0.0.0.0 이다"| F["서버는 받을 준비가 됐다 · 방화벽이나 망을 본다"]
셋째는 연결이 자꾸 쌓인다는 의심이 들 때입니다. 상태마다 줄 수를 세면 어느 쪽인지 드러납니다.
$ netstat -tan | grep CLOSE_WAIT | wc -l
grep 은 그 상태의 줄만 남깁니다. wc -l 은 남은 줄 수를 셉니다.
CLOSE_WAIT 가 시간이 갈수록 늘면 「TCP 연결 상태」 소절에서 본 대로 프로그램이 소켓을 안 닫고 있습니다.
한 프로세스가 데이터베이스 포트로 맺은 ESTABLISHED 가 그 프로세스의 커넥션 풀 크기보다 많으면 풀 밖에서 연결을 여는 코드가 있습니다.
ss · lsof · tcpdump 와 나눠 맡는 일
netstat 가 찍는 것은 친 순간의 목록 한 장입니다. 1초 안에 맺고 끊는 연결은 치는 때를 잘 맞추지 않으면 안 보입니다. 오간 데이터의 내용도 안 보입니다. 누가 누구와 이어졌는지만 보입니다.
리눅스에서는 ss(socket statistics, 소켓 통계)라는 새 명령이 netstat 의 연결 목록 일을 이어받았습니다. ss 의 옵션 글자는 netstat 와 대부분 같습니다.
netstat -tlnp 는 ss -tlnp 로 그대로 옮겨 칠 수 있습니다. 연결이 아주 많은 서버에서는 ss 가 훨씬 빨리 끝납니다.
netstat 는 net-tools 라는 도구 묶음에, ss 는 iproute2 라는 묶음에 들어 있습니다. 요즘 리눅스 배포판 가운데는 net-tools 를 기본으로 깔지 않는 것이 많습니다. 그런 서버에서 netstat 를 치면 명령이 없다는 에러가 납니다.
비슷한 진단 명령과는 아래처럼 나눠 맡습니다.
| 명령 | 알려 주는 것 |
|---|---|
| netstat | 이 컴퓨터의 소켓 목록 · 라우팅 테이블 · 인터페이스와 프로토콜 통계 |
| ss | 소켓 목록. 리눅스에서 netstat 의 연결 목록을 이어받았다 |
| lsof | 프로세스가 연 파일 목록. 소켓도 파일로 보여 포트의 주인을 찾을 때 쓴다 |
| tcpdump | 오가는 패킷의 내용 |
관련 항목
netstat 가 목록으로 보여 주는 대상
소켓 · 리슨 소켓 · 포트 · 임시 포트 · IP 주소 · 루프백 · 네트워크 인터페이스 · 유닉스 도메인 소켓
netstat 가 State 칸에 찍는 TCP 상태
TCP 상태 · TIME_WAIT · CLOSE_WAIT · 3방향 핸드셰이크 · 4방향 핸드셰이크 · TCP
netstat 가 연결 목록 말고 찍는 표와 그 안의 값
경로표 · 기본 게이트웨이 · 게이트웨이 · 재전송 · 패킷 손실
netstat 와 진단을 나눠 맡는 명령과 그 도구 묶음
ss · lsof · tcpdump · Wireshark · ip route · ifconfig · traceroute · ping · net-tools · iproute2
netstat 로 짚어 내는 서버 문제
EADDRINUSE · 커넥션 누수 · 포트 고갈 · SYN 플러드
netstat 로 본 문제를 풀거나 일으키는 설정
커넥션 풀 · 바인드 · 방화벽 · 컨테이너 · keep-alive
다른 이름: network statistics · netstat 명령 · 넷스탯