Network Programming for Microsoft Windows
TCP 상태 변화 (TCP States)
모든 소켓의 시작 상태는 CLOSED이다 클라이언트가 연결을 시도할 때 클라이언트는 SYN 패킷을 서버에 전송한다. 이때 클라이언트는 SYN_SENT 상태가 된다. 서버가 SYN 패킷을 받으면 SYN-ACK 패킷으로 응답하는데 응답을 받은 클라이언트는 ESTABLISHED 상태가 된다. 만일 서버가 SYN-ACK으로 응답하지 않으면 클라이언트는 타임아웃(timeout)되고 CLOSED 상태로 되돌아간다.
서버의 소켓이 바인트(bind)되고 연결대기(listen)중이라면 소켓의 상태는 LISTEN이 된다. 클라이언트가 연결을 시도할 때 서버는 SYN 패킷을 받게 되고 서버는 SYN-ACK 패킷으로 응답한다. 이때 서버 소켓은 SYNC_RCVD 상태가 된다. 마지막으로 클라이언트가 ACK 패킷을 보내오면 서버 소켓의 상태는 ESTABLISHED 상태가 된다.
ESTABLISH 상태가 된 소켓은 두 가지 경로를 통하여 종료된다. 보통 응용프로그램을 종료할 때는 소켓의 능동종료(active socket closure)라고 불리는 과정이 일어나고 그렇지 않은 경우는 수동 종료(passive closure) 과정이 일어난다. 능동적 종료의 경우는 연결 종료를 시도하는 응용프로그램에서 먼저 FIN 패킷을 전송한다. 이 과정은 다음과 같다. 응용프로그램에서 소켓에 대하여 closesocket이나 shutdown(두번째 인자로 SD_SEND를 사용한 경우)을 호출한 경우 연결된 상대방으로 FIN 패킷이 전송되고 소켓의 상태는 FIN_WAIT1 상태가 된다. 일반적으로 이때 상대방은 ACK으로 응답하게 되고 소켓의 상태는 FIN_WAIT2 상태가 된다. 만일 상대방도 소켓을 종료하게 되면 상대방으로부터 FIN 패킷이 전송되고 응용프로그램의 소켓은 ACK으로 응답하게 된다. 이때 소켓의 상태는 TIME_WAIT가 된다.
TIME_WAIT 상태는 2MSL 대기 상태(2MSL wait status)라고도 한다. MSL(Maximum Segment Lifetime)이란 패킷이 폐기되기 전에 네트웍에서 살아있을 수 있는 시간이다. 모든 IP 패킷들은 TTL(time-to-live)이라는 값을 가진다. TTL이 0이 되면 그 패킷은 폐기된다. 모든 라우터들은 패킷을 통과시키면서 이 TTL값을 1만큼 감소시킨다. 소켓이 TIME_WAIT 상태가 되면 MSL의 두 배만큼의 시간동안 TIME_WAIT 상태로 대기한다. 이로 인해 ACK패킷이 앞서 설명한 TTL에 의하여 소실된 경우에도 ACK패킷을 재전송하여 FIN 패킷이 재전송될 수 있다. 2MSL 상태가 끝나면 소켓은 대기상태에서 CLOSED상태로 바뀐다.
능동종료(active socket closure)에서 소켓의 상태가 TIME_WAIT가 되는 과정은 두 가지가 있다. 앞의 설명에서, 한쪽에서만 FIN 패킷을 전송하고 응답으로 ACK 패킷을 받았다면 상대방은 자신이 종료하기 전까지 패킷을 전송하는 것이 가능하다. 이런 이유로 두 가지 경우가 생긴다. 한 가지 경우는 – 동시종료 – 양쪽에서 동시에 종료하는 경우다. 어떤 컴퓨터에서 종료를 시도하고 상대방도 종료를 시도한다고 하자. 컴퓨터에서는 FIN 패킷을 전송했고 상대방이 보낸 FIN 패킷을 수신했다. 컴퓨터는 FIN에 대한 응답으로 ACK을 전송할 것이고 소켓의 상태는 CLOSING으로 바뀐다. 컴퓨터가 마지막 ACK 패킷을 받게 되면 소켓의 상태는 TIME_WAIT가 된다.
또 다른 능동 종료의 경우는 동시 종료의 변종으로 소켓의 상태가 FIN_WAIT_1 상태에서 TIME_WAIT 상태로 바로 변하는 경우다. 이 경우는 응용 프로그램이 FIN 패킷을 보낸 후 아주 짧은 시간 안에 FIN-ACK 패킷을 받는 경우이다(FIN-ACK는 하나의 패킷에 FIN과 ACK 필드의 값이 동시에 설정된 경우이다). 이 경우 상대방은 FIN 패킷을 받고 응답으로 ACK 패킷을 보내면서 자신도 FIN 패킷을 보낸 경우다.
TIME_WAIT 상태는 TCP연결을 2MSL 대기 상태로 만든다. 이때는 이 연결에 해당되는 소켓쌍(socket pair)은 재사용이 불가능한 것이 원칙이다. 소켓쌍은 로컬 IP – 로컬 포트 그리고 리모트 IP – 리모트 포트의 조합이다. TIME_WAIT상태에 있는 소켓쌍에 대한 연결 시도는 WSAEADDRINUSE 를 발생시키며 실패한다. 소켓쌍이 TIME_WAIT 상태로 남겨져서 재빨리 로컬 포트를 재사용하지 못하는 것을 피하는 유일한 방법은 SO_REUSEADDR 옵션을 사용하는 것이다.
수동 종료(passive closure). 이 시나리오는 다음과 같다. 응용프로그램이 상대방으로부터 FIN패킷을 받고 ACK패킷으로 응답한다. 이때 응용프로그램의 소켓은 CLOSE_WAIT 상태가 된다. 상대방은 연결을 종료했으므로 더 이상 패킷을 보내지 못한다. 하지만 응용프로그램은 자신이 연결을 종료하기 전까지 패킷을 보낼 수 있다. 응용프로그램이 연결을 종료할 때 FIN 패킷을 보내고 소켓의 상태는 LAST_ACK이 된다. 응용프로그램이 상대방으로부터 ACK 패킷을 받게 되면 소켓의 상태는 CLOSED가 된다.
TCP/IP에 대한 자세한 설명은 RFC793을 참조. RFC는 http://www.rfc-editor.org
소켓의 종료 상태
소켓의 상태 변화
'프로그래밍' 카테고리의 다른 글
Herb Sutter: (Not Your Father’s) C++ (0) | 2013.05.23 |
---|---|
FILETIME (0) | 2013.05.16 |
gtest 사용하기 (0) | 2012.12.06 |
FormatMessage (Win32) (0) | 2012.12.05 |
include 가드 (0) | 2012.12.05 |