TCP의 연결 종료 절차는 연결 절차(three-way handshake)와 다르게 4가지 절차로 이뤄져 있습니다.
흔히 연결 종료 절차를 4-way handshake라고 부르더라구요. RFC에 공식적으로 적혀있는 용어는 아니였습니다.
FIN을 전송하는 것은 상대방에게 "난 더 이상 보낼 데이터가 없다" 고 알리는 행위입니다.
따라서 FIN을 서로 주고받는 것이 연결 종료를 의미하는 것 입니다.
하지만 이 FIN을 두 Peer가 주고받는게 아니라 한쪽만 보내면 어떻게 될까요?
다시 말해서 4-way handshake의 4가지 절차에서 절반만 수행하면 어떻게 되는 걸까요??
바로 FIN을 보낸 Peer는 데이터를 전송할 수 없지만, 다른 Peer는 데이터를 보낼 수 있는 상태가 됩니다!
즉 양방향 데이터 전송이 가능한 Full-Duplex TCP 연결이,
단방향으로만 데이터 전송이 되는 Half-Duplex TCP 연결이 되는 것 입니다.
이러면 명시적으로 데이터의 방향성을 지정할 수 있으니 특정한 소켓 프로그래밍 상황에서 굉장히 유용할거라는 생각이 들었습니다. 왜냐면 단방향으로만 데이터를 보내야 하는 경우에, Flag변수 등을 이용해 Full-Duplex Connection을 논리적으로 Half-Duplex Connection으로 사용하는게 아니라,
Half-Close를 통해 Half-Duplex Connection으로 전환하면 더 개발 소요가 줄어들 것이기 때문입니다.
하지만 Half-Closed Connection에도 단점은 존재합니다.
그 단점은 바로 Half-Closed Connection의 불안정성입니다.
Half-Closed Connection 상태에서는 FIN을 보낸 피어의 TCP State가 FIN-WAIT-2 상태로 돌입합니다.
TCP가 네트워크 통신인 만큼, 어떤 상황에서 상대방과의 연결이 끊킬지 모릅니다. 근데 FIN-WAIT-2 에서 상대방과 연락 두절되면, 서버는 연결되지 않는 상대방을 기다리느라 운영체제의 Connection 자원을 소모하게 됩니다.
마치 Syn-Flooding 처럼 의도적인 DOS 공격도 가능하겠네요.
실제로도 FIN-WAIT-2는 유명한 문제고, 이 때문에 대부분의 unix 운영체제는 FIN-WAIT-2 상태에 대한 타임아웃을 설정할 수 있습니다.
다만 이런 TIMEOUT 임의 설정은 TCP의 공식 규약에 위반되는 행위입니다.
하지만 이런 특정 문제를 해결하기 위해 서버나 네트워크 장비, 보안 장비에서 이런 설정을 제공합니다.
원래대로라면 2*MSL(Maximun Segment Lifetime) 만큼 FIN-WAIT-2 상태를 유지해야 하지만, 운영체제 설정이나, 피어 사이에 있는 네트워크 장비, 보안 장비등의 네트워크 설정으로 인해 2*MSL이라는 시간이 보장되는건 아닙니다.
따라서 Half-Closed Connection은 앵간해서는 사용하지 않는게 좋고, 사용 하더라도 FIN-WAIT-2 상태를 연장시켜주기 위해 매우 짧은 간격의 Health Check가 구현되어야 할 것 같네요.