Graceful shutdown, linger options and socket closure

이 문서는 소켓의 접속을 셧다운 하는 것과 소켓을 닫는(close)것이라는 주제에 대해서 그 의미를 명확히 하기위해 제공되는 문서입니다. 소켓의 접속을 셧다운(shutting down)하는 것과 소켓을 닫는(close)것의 사이를 구분짖는 것은 매우 중요합니다. 소켓의 접속을 셧다운 한다는 것의 의미는 연결된 두 단말사이의 큐에 버퍼링 되어 있는 메시지를 주고 받는다는 것을 의미합니다. 셧다운 작업은 일반적으로 우아한(graceful)것과 중지(abortive or hard)로 크게 두가지 부분으로 정의 되어 있습니다.

여기서 잠깐! 컴퓨터 관련 문서를 많이 접해 보신분들은 위에서 설명한 graceful 이나 hard 라는 단어에 대해서 익숙하실 겁니다. 하지만, 그렇지 못하신 분들은 이게 먼소리냐고 할지도 모릅니다. 일반적으로 가장 이상적으로 동작하게 되는 형태를 "graceful ...." 한 작업이라고 칭하게 됩니다. 굳이 한국말로 표현하자면, 우아한 ... 가 되겠죠... 반면에 이상적이 형태가 아닌 묵시적이거나 바람직하지 않은 방향으로 처리되는 작업을 "hard ..."라 칭하게 됩니다.

우아한 셧다운의 처리과정에서 큐에 버퍼링 되었지만, 아직 전송되지 않은 데이터는 접속이 종료되기 전에 보내지게 됩니다. 중지처리되는 셧다운의 처리과정에서 이러한 아직 보내지지 않은 데이터는 손실되게 됩니다. 하지만, 셧다운이 되었다고 해서 소켓에 할당된 리소스나 소켓 핸들이 반환 되었다는 것을 의미하지는 않습니다. 즉, 소켓을 닫는다(closing)는 것은 할당된 소켓핸들을 해제(반환) 한다는 것을 의미합니다. 소켓핸들이 해제되었으므로 어떻한 방법으로든 이 해제된 소켓을 사용할 수 없습니다.

윈도즈 소켓에서 shutdown 함수와 WSASendDisconnect 함수는 모두 셧다운 처리과정을 시작하는데 사용할 수 있습니다. 반면에 closesocket 함수는 할당받은 소켓핸들을 해제해고, 할당받은 관련된 리소스들을 해제 하는데 사용됩니다. 그런데 일반적인 프로그래밍 할 때 보면, closesocket 함수가 셧다운 처리과정을 발생시킬 것이라고 하여 사용됩니다. 이러한 점은 우리를 매우 헷갈리게 만들죠, 사실상 closesocket 함수는 셧다운 처리과정을 시작하고, 소켓 핸들을 해제하는 작업 모두에 사용된다고 합니다.

SO_LINGER 와 SO_DONTLINGER 소켓옵션에 대한 적절한 값을 설정 했을경우, closesocket 함수로 아래와 같은 처리의 경우를 얻어낼 수 있습니다.

접속이 해제되는 동안 발생할 수 있는 문제점을 최소화 하려면, closesocket 함수를 호출해서 암시적으로 셧다운 되는 작업을 하는 것을 피하는 것입니다. closesocket 대신에 shutdown 이나 WSASendDisconnect 함수를 명시적으로 사용하는 방법이 있습니다.

아래의 표는 우아한 셧다운을 시작하기 위한 서버와 클라이언트의 함수사용의 순서를 보여줍니다.

Client Side Server Side
(1) 세션을 종료하기 위해서 shutdown(s, SD_SEND) 함수를 호출합니다. 그리고, 클라이언트는 더 이상 보낼데이터를 가지고 있지 않고 보내지도 않는 다고 가정합시다.  
  (2) FD_CLOSE 메시지를 수신받고, 우아한 셧다운은 진행상태에 들어갑니다. 그리고, 수신해야 할 데이터는 모두 수신받습니다.
  (3) 남아있는 응답 데이터를 전송합니다.
(5') FD_READ 메시지를 얻어내고, 서버로부터 보내진 데이터를 얻어내기 위해 recv 함수를 호출합니다. (4) 서버는 더 이상 보낼 데이터가 없도록 내부 큐를 비우기 위해 sutdown(s, SD_SEND) 함수를 호출합니다.
(5-2) FD_CLOSE 메시지를 수신합니다. (4') closesocket 함수를 호출합니다.
(6) closesocket 함수를 호출합니다.