TCP 연결 종료와 TIME_WAIT 상태 이해하기

TCP 4-Way Handshaking의 FIN·ACK 흐름과 TIME_WAIT의 역할, 연결 종료 시 발생하는 소켓 관리 이슈를 정리합니다.

2026-08-14 · 최초 발행 2025-07-16

TCP 연결은 양쪽이 각자의 송신 방향을 닫는다

TCP는 연결 지향 프로토콜이므로 연결을 만들 때뿐 아니라 해제할 때도 상태 전이가 필요하다. 종료 과정에서는 한쪽이 더 이상 데이터를 보내지 않겠다는 의사를 밝아도, 반대편의 전송은 남아 있을 수 있다. 그래서 양방향 통신 채널을 각각 닫으며 데이터 손실 없는 종료를 보장한다.

FIN과 ACK가 오가는 종료 흐름

연결이 활성화된 상태에서 클라이언트가 먼저 종료를 시작하면, 서버의 응답과 별도 종료 요청을 거쳐 클라이언트의 최종 확인으로 끝난다.

ServerClientServerClient활성화된 연결 상태FIN_WAIT_1 상태FIN_WAIT_2 상태CLOSE_WAIT 상태LAST_ACK 상태TIME_WAIT 상태CLOSED 상태(2MSL 후) CLOSED 상태1. FIN (seq:100, ack:-)2. ACK (seq:2000, ack:101)3. FIN (seq:2000, ack:101)4. ACK (seq:101, ack:2001)

클라이언트는 FIN 플래그가 설정된 세그먼트에 시퀀스 번호 seq=100을 담아 보낸 뒤 FIN_WAIT_1으로 전환한다. 서버는 이를 받은 뒤 seq=2000, ack=101을 포함한 ACK를 반환한다. ack=101은 클라이언트 시퀀스 번호에 1을 더한 값이며, 이때 서버는 CLOSE_WAIT, 클라이언트는 FIN_WAIT_2 상태가 된다.

서버 애플리케이션의 종료 처리가 끝나면 서버는 seq=2000, ack=101을 담은 FIN을 보내고 LAST_ACK로 이동한다. 클라이언트는 서버 FIN을 확인하는 ACK를 seq=101, ack=2001로 전송한다. ack=2001은 서버 시퀀스 번호에 1을 더한 값이다. 서버는 ACK를 수신하면 CLOSED가 되고, 클라이언트는 TIME_WAIT을 거친 뒤 2MSL 후 CLOSED가 된다.

TIME_WAIT이 남아 있는 이유

TIME_WAIT은 단순한 대기 상태가 아니다. 네트워크에 남아 지연된 패킷이 도착할 가능성을 처리하고, 마지막 ACK가 유실됐을 때 서버가 재전송하는 FIN에도 응답할 수 있게 한다. 같은 IP 주소와 포트로 이루어진 소켓 페어가 곧바로 재사용되는 것도 막는다.

이 상태는 일반적으로 2MSL(Maximum Segment Lifetime) 동안 유지된다. 이는 패킷이 네트워크에 존재할 수 있는 최대 시간의 2배이며, 일반적으로 30초~4분 정도가 된다.

연결 종료가 운영 부담이 되는 경우

연결이 자주 닫히는 환경에서는 TIME_WAIT 소켓이 빠르게 쌓일 수 있다. 시스템 리소스 점유가 늘어나 메모리 부족 현상이 생기거나 서버의 소켓 처리 용량을 넘길 가능성도 있다.

서버가 네트워크 장애나 충돌로 FIN을 보내지 못한 채 LAST_ACK에서 CLOSED로 바뀌는 경우도 문제다. 클라이언트는 불필요하게 TIME_WAIT을 유지하게 되고, 리소스 낭비와 소켓 리스닝 지연이 이어질 수 있다. 2MSL 대기 시간이 긴 경우에는 높은 처리량이 필요한 서버에서 소켓 재사용이 늦어져 성능 저하로 이어진다.

소켓 종료 부담을 다루는 설정과 방식

시스템의 트래픽 패턴과 서버 환경에 맞춰 TIME_WAIT 지속 시간을 조정할 수 있다.

# Linux 시스템에서 TIME_WAIT 타임아웃 조정 예
sysctl -w net.ipv4.tcp_fin_timeout=30

소켓 재사용 옵션은 TIME_WAIT 상태의 소켓을 즉시 재사용하도록 설정하며, 부하가 높은 서버에서 리소스 효율을 높이는 방법이 된다.

// C 언어 소켓 프로그래밍 예제
int reuse = 1;
setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));

클라이언트가 FIN과 ACK를 동시에 보내는 방식으로 구현하면 4단계를 3단계로 줄여 대기 시간을 낮출 수 있다. 프로토콜 최적화를 통한 성능 향상 방식이다.

비정상 종료를 더 빨리 감지하려면 TCP keepalive를 활용할 수 있다.

# Linux 시스템에서 keepalive 설정 예
sysctl -w net.ipv4.tcp_keepalive_time=60
sysctl -w net.ipv4.tcp_keepalive_intvl=10
sysctl -w net.ipv4.tcp_keepalive_probes=6

연결 상태를 주기적으로 확인하면 불필요한 TIME_WAIT 상태를 줄이는 데 도움이 된다.

웹 서버와 금융 시스템에서의 연결 관리

Nginx 같은 고성능 웹 서버는 작업자 프로세스 모델로 연결을 분산하고, 이벤트 기반 비동기 처리로 소켓을 관리한다. keepalive 연결도 설정으로 최적화할 수 있다.

# Nginx 설정 예제
http {
    keepalive_timeout 65;
    keepalive_requests 100;
    reset_timedout_connection on;
}

실시간 트랜잭션 처리가 중요한 금융 시스템에서는 클러스터링으로 단일 서버의 TIME_WAIT 부담을 낮추고, 소켓 풀링(Socket Pooling)으로 연결 재사용을 최적화한다. 소켓 상태를 실시간으로 감시해 이상 징후를 찾는 모니터링 시스템도 함께 사용한다.

연결 수립과 종료가 다른 이유

4-Way Handshaking(연결 종료)FINACKFINACK클라이언트서버3-Way Handshaking(연결 수립)SYNSYN+ACKACK클라이언트서버

연결 수립은 양방향 통신 채널을 한 번에 설정하므로 3단계로 충분하다. 반면 연결 종료에서는 양방향 채널을 각각 독립적으로 닫아야 하므로 4단계가 필요하며, 이 추가 과정은 데이터 손실을 방지하는 역할을 한다.

TCP/IP네트워크연결 종료TIME_WAIT소켓프로토콜