TCP 소켓에는 총 11가지의 상태가 있고(netstat를 이용해 소켓의 상태를 보면 CLOSED, LISTEN, SYN_SENT, SYN_RECV, ESTABLISHED, CLOSE_WAIT, LAST_ACK, FIN_WAIT1, FIN_WAIT2, CLOSING, TIME_WAIT..중에 하나가 나온다) 그 중 사람들이 자주 헷갈리는 것이 TIME_WAIT와 CLOSE_WAIT는 요 두가지 상태이다.
오늘은 이 TIME_WAIT와 CLOSE_WAIT, 요 두 상태에 대해 말해 보도록 하겠다.
들어가기에 앞서, 용어 정리를 먼저 하도록 하자.
- Active Open : connect()를 호출 하는 쪽. 즉, SYN 세그먼트를 전송한 쪽. 종종 클라이언트가 된다.
하지만 100% 클라이언트라고 할 수는 없다. - Passive Open : accept()를 호출 하는 쪽. 일반적으로 서버의 역할이다. 이 역시 100% 서버라고 단정지을 수는 없다.
- Active Close : close()를 처음 호출 한 쪽. 즉 FIN 세그먼트를 전송 한쪽. 클라이언트, 서버 관계 없이 어느 쪽이든 다 active close를 할 수 있다
- Passive Close : FIN 세그먼트를 받은 쪽.
- MSL : maximum segment lifetime, 세그먼트가 네트워크내에서 폐기 되기 전까지 살아남을 수 있는 시간
Active Close를 하는 쪽(close() 함수를 호출한 쪽)은 TIME_WAIT상태가 되며, Passive Close 를 하는 쪽(FIN을 수신한 쪽)은 CLOSE_WAIT 상태가 된다. 아래 그림에서 A는 Active Close, B는 Passive Close를 하는 쪽이다 :
※ active close, passive close에 서버, 클라이언트 구분이 없는 것에 대해 주목하자.
TIME_WAIT 상태... 뭐할려고 있는가?
1. Active Close하는 쪽의 마지막 ACK가 소실 되었을 때, Passive Close하는 쪽은 자신이 보낸 FIN에 대한 응답을 받지 못했으므로 FIN(SEQ:6001, ACK:5001)을 재전송한다. 이 때 TCP는 connection 정보(주소와 포트)를 유지하고 있고, 이런 이유로 RST(에러라고 처리되는 세그먼트) 대신 ACK를 다시 보낼수가 있다.
2. 확률이 극도로 희박하긴 하지만 네트워크를 방황하던, Passive Close하는 쪽에서 보낸 중복된 FIN 메시지가 나중에 다시 생긴 connection에 영향을 주는 것을 방지하기 위해서 TIME_WAIT 상태를 2MSL 동안 유지한다.
그럼 CLOSE_WAIT 상태는?
CLOSE_WAIT는 Passive Close하는 쪽(FIN을 받는 쪽)에서 프로그램이 소켓을 종료 시키는 것을 기다리기위한 상태이다. 프로그래밍 관점에서 말하면, recv byte가 0으로 연결이 끊어 졌으나 close() 함수가 호출 되지 않은 상태라고 생각하면 된다.
TCP connection은 close() 함수가 명시적으로 호출되지 않으면 CLOSE_WAIT 상태에서 영원히 멈춰 있을 수 있고 이것은 자원 누수로 이어진다. 소켓 사용하고 나면 close()를 명시적으로 호출 해 주어야만 한다.
ref.
- A Word on TIME_WAIT and CLOSE_WAIT