백엔드 면접 용어 사전
네트워크

CLOSE_WAIT

FIN을 받고도 애플리케이션이 close()를 호출하지 않아 머무는 상태. 쌓이면 대개 앱의 버그다.

상대의 FIN을 받아 ACK까지 보냈지만, 내 쪽 애플리케이션이 아직 close()를 호출하지 않은 상태.

어느 지점인가

상대 ──── FIN ────► 나
나   ──── ACK ────► 상대        ← 여기서 내 소켓은 CLOSE_WAIT
                                 (커널은 할 일을 다 했다)
나   : close() 호출 필요 ─────┐
                              ▼
나   ──── FIN ────► 상대     LAST_ACK → 종료

커널은 "상대가 닫았다"까지만 처리하고, 애플리케이션이 소켓을 닫아 주기를 기다린다. 아직 보낼 데이터가 남았을 수도 있으니 커널이 마음대로 닫을 수 없기 때문이다.

쌓이면 100% 버그다

TIME_WAIT는 시간이 지나면 사라지지만, CLOSE_WAIT는 close()를 부르기 전까지 영원히 남는다. 그래서 개수가 단조 증가한다면 코드 문제다.

흔한 원인

// ❌ 예외가 나면 close 가 안 된다
InputStream in = socket.getInputStream();
process(in);          // 여기서 예외
in.close();

// ✅ try-with-resources
try (InputStream in = socket.getInputStream()) {
    process(in);
}
  • 예외 경로에서 close() 누락
  • 커넥션 풀에서 빌린 자원 미반납
  • HTTP 클라이언트에서 응답 본문을 안 읽거나 안 닫음 (본문을 다 읽어야 커넥션이 풀로 돌아가는 구현이 많다)

어떻게 터지나

소켓 하나가 파일 디스크립터 하나다. CLOSE_WAIT이 쌓이면 FD 한도에 걸려

java.net.SocketException: Too many open files

가 나고, 그 시점엔 새 연결도 파일 열기도 전부 실패한다. 서버가 통째로 멈춘다.

진단 순서

ss -tan state close-wait | wc -l     # 개수 추이
lsof -p <PID> | wc -l                # 프로세스별 FD 수
ulimit -n                            # 한도 확인

개수가 계속 늘어나면 어느 코드 경로가 닫지 않는지를 찾는다. 상대 포트를 보면 어떤 외부 시스템과의 연결인지 좁힐 수 있다.

함께 보면 좋은 용어

노트에서 맥락과 함께 보기 — 네트워크 — TCP/UDP·핸드셰이크·HTTP·HTTPS