base
TCP(Transmission Control Protocol)는 신뢰성 있는 연결 지향형 통신을 제공하기 위해 설계된 프로토콜로, 연결을 설정하고 데이터를 주고받은 뒤에는 반드시 정상적인 연결 종료 과정을 거칩니다. 많은 개발자들이 연결을 여는 과정인 3-Way Handshake는 잘 알고 있지만, 연결을 닫는 과정인 4-Way Handshake는 다소 생소할 수 있습니다. 그러나 연결 종료 역시 설정만큼이나 중요하며, 잘못된 종료는 데이터 유실이나 시스템 리소스 낭비로 이어질 수 있습니다.
이 글에서는 TCP 연결 종료 시 수행되는 4단계의 과정을 자세히 살펴보고, 왜 TCP가 연결 해제를 이처럼 신중하게 처리하는지를 기술적으로 정리해 봅니다.
TCP는 양방향 스트림 기반 프로토콜입니다. 즉, 클라이언트와 서버는 서로 독립적으로 데이터를 송수신할 수 있는 상태를 유지합니다. 이 때문에 어느 한쪽이 데이터를 더 이상 보내지 않더라도, 다른 한쪽은 계속 데이터를 보낼 수 있습니다. 이러한 이유로, 연결을 완전히 종료하려면 양방향 모두에 대해 독립적인 종료 절차를 수행해야 합니다. 이로 인해 TCP는 4-Way Handshake라는 4단계 종료 과정을 채택합니다.
다음은 TCP에서 연결을 해제하는 4단계의 흐름입니다:
연결을 종료하려는 측(A)은 FIN 플래그가 설정된 TCP 세그먼트를 B에게 전송합니다. 이는 “더 이상 전송할 데이터가 없습니다”라는 의사 표현입니다. 이때 A는 반쪽 닫기(Half-Close) 상태로 전환되며, 수신은 계속 가능하지만 송신은 불가능합니다.
B는 A로부터 받은 FIN 요청에 대해 ACK 응답을 보냅니다. 이는 “당신이 더 이상 데이터를 보내지 않겠다는 의사를 확인했다”는 의미입니다. 하지만 B는 여전히 데이터를 전송할 수 있으며, A는 그 데이터를 수신할 수 있습니다.
B도 자신의 데이터 전송이 완료되었다고 판단되면, 자신의 FIN 플래그가 설정된 세그먼트를 A에게 전송합니다. 이는 “나도 데이터를 더 이상 보내지 않겠다”는 의사 표현입니다.
A는 B의 FIN에 대해 확인 응답 ACK를 전송하고, 이로써 양방향 데이터 흐름이 모두 종료되며 TCP 연결은 완전히 닫힙니다.
FIN과 ACK가 각각 두 번씩 오가는 이유는 TCP가 양방향 통신 채널을 유지하기 때문입니다. 한 방향에서 송신이 끝났다고 해서 다른 방향의 데이터 흐름도 자동으로 종료되는 것이 아닙니다. 따라서 A → B 방향의 종료와 B → A 방향의 종료는 서로 독립적인 절차로 처리됩니다.
이러한 구조는 잔여 데이터가 완전히 전송되고 수신될 수 있는 시간을 확보해주며, 특히 지연된 패킷 처리나 버퍼에 남은 데이터 전송을 보장할 수 있습니다.
TCP는 단순한 연결을 넘어, 신뢰성과 데이터 정합성을 보장하기 위해 설계된 프로토콜입니다. 종료 단계에서도 이러한 특성을 유지하기 위해 다음과 같은 설계 원칙이 적용됩니다.
TCP 종료 절차가 없거나 부정확하게 처리되면, 시스템은 '좀비 연결(zombie connection)'을 유지하거나 중간에 유실된 데이터로 인해 애플리케이션 레벨에서 문제가 발생할 수 있습니다.
네트워크 개발자나 인프라 엔지니어가 실제 환경에서 TCP 종료 절차를 분석할 때는 Wireshark 같은 툴을 활용합니다. 이를 통해 다음과 같은 항목을 확인할 수 있습니다.
이러한 분석은 장애 원인 파악이나 성능 튜닝, 또는 애플리케이션의 정상 종료 여부를 판단하는 데 매우 중요합니다.
TCP 연결을 종료할 때는 송신과 수신 양쪽 스트림을 차례로 닫으며, 데이터 손실 없이 통신을 마무리하기 위해 네 번의 제어 메시지를 주고받습니다. 먼저 연결을 닫고자 하는 쪽이 FIN 플래그를 설정한 패킷을 보내 “이제 이 방향으로는 보낼 데이터가 더 없다”고 알리고, 상대방은 이를 받으면 ACK로 “FIN을 잘 받았음”을 응답합니다. 그다음 상대방도 자신의 전송 스트림을 종료하기 위해 또 한 번 FIN을 보내고, 처음 FIN을 보낸 쪽은 마지막으로 ACK를 전송해 “내 FIN도 잘 받았음”을 확인합니다. 이후 ACK를 보낸 쪽은 일정 시간 동안 TIME_WAIT 상태로 머물러 재전송된 패킷이 남아 있더라도 처리할 수 있도록 함으로써, 양방향으로 남은 모든 데이터가 확실히 전송된 후에야 연결을 완전히 해제합니다.