정상 종료, 느린 옵션 및 소켓 닫기

다음 자료는 소켓을 닫는 소켓 연결을 종료하는 주제에 대한 설명으로 제공됩니다. 소켓 연결을 종료하는 것과 소켓을 닫는 것의 차이를 구분하는 것이 중요합니다.

소켓 연결을 종료하려면 두 엔드포인트 간의 프로토콜 메시지 교환이 포함되며, 그 후에는 종료 시퀀스라고 합니다. 종료 시퀀스의 두 가지 일반 클래스인 정상 및 중단(하드라고도 함)이 정의됩니다. 정상적인 종료 시퀀스에서는 연결이 닫기 전에 큐에 대기되었지만 아직 전송되지 않은 모든 데이터를 보낼 수 있습니다. 중단된 종료에서는 전송되지 않은 데이터가 손실됩니다. 종료 시퀀스(정상 또는 중단)의 발생을 사용하여 종료가 진행 중임을 나타내는 관련 애플리케이션에 FD_CLOSE 표시를 제공할 수도 있습니다.

반면 소켓을 닫으면 소켓 핸들의 할당이 취소되어 애플리케이션이 더 이상 어떤 방식으로든 소켓을 참조하거나 사용할 수 없게 됩니다.

Windows 소켓에서 shutdown 함수와 WSASendDisconnect 함수를 모두 사용하여 종료 시퀀스를 시작할 수 있으며 closesocket 함수는 소켓 핸들의 할당을 취소하고 연결된 리소스를 해제하는 데 사용됩니다. 그러나 closesocket 함수가 아직 발생하지 않은 경우 종료 시퀀스가 암시적으로 발생한다는 사실 때문에 약간의 혼란이 발생합니다. 실제로 이 기능을 사용하고 closesocket 을 사용하여 종료 시퀀스를 시작하고 소켓 핸들의 할당을 취소하는 것이 일반적인 프로그래밍 관행이 되었습니다.

이 사용을 용이하게 하기 위해 소켓 인터페이스는 프로그래머가 암시적 종료 시퀀스를 정상 또는 중단해야 하는지 여부를 나타내고, 정상적인 종료 시퀀스가 완료될 시간을 허용하기 위해 closesocket 함수가 남아 있어야 하는지(즉시 완료되지 않음) 여부를 나타내는 소켓 옵션 메커니즘을 통해 컨트롤을 제공합니다. 이러한 중요한 차이점과 이러한 방식으로 closesocket 을 사용하는 파급 효과는 여전히 널리 이해되지 않습니다.

SO_LINGER 및 SO_DONTLINGER 소켓 옵션에 적절한 값을 설정하면 closesocket 함수를 사용하여 다음 유형의 동작을 얻을 수 있습니다.

  • 중단 종료 시퀀스이며 closesocket에서 즉시 반환됩니다.
  • 정상 종료, 종료 시퀀스가 완료되거나 지정된 시간 간격이 경과할 때까지 반환을 지연합니다. 정상 종료 시퀀스가 완료되기 전에 시간 간격이 만료되면 중단 종료 시퀀스가 발생하고 closesocket이 반환됩니다.
  • 정상 종료, 즉시 반환 - 백그라운드에서 종료 시퀀스를 완료할 수 있습니다. 기본 동작이지만 애플리케이션은 정상적인 종료 시퀀스가 실제로 완료되는 시기(또는 여부)를 알 수 없습니다.

SO_LINGER 및 SO_DONTLINGER 소켓 옵션 및 연결된 느린 구조체의 사용은 SOL_SOCKET 소켓 옵션느린 구조에 대한 참조 섹션에서 자세히 설명합니다.

연결 해제 중에 발생하는 문제를 최소화하는 데 사용할 수 있는 한 가지 기술은 closesocket에서 시작되는 암시적 종료에 의존하지 않는 것입니다. 대신 두 명시적 종료 함수인 shutdown 또는 WSASendDisconnect 중 하나를 사용합니다. 그러면 보류 중인 모든 데이터가 수신되었음을 나타내는 피어 애플리케이션에서 FD_CLOSE 표시가 수신됩니다. 이를 설명하기 위해 다음 표에서는 클라이언트가 정상 종료를 시작할 책임이 있는 애플리케이션의 클라이언트 및 서버 구성 요소에서 호출할 함수를 보여 줍니다.

클라이언트 쪽 서버 쪽
(1) 종료를 호출하여 SD_SEND 세션 종료를 알리고 클라이언트에 보낼 데이터가 더 이상 없습니다.
(2) 진행 중인 정상 종료 및 모든 데이터가 수신되었음을 나타내는 FD_CLOSE 받습니다.
(3) 나머지 응답 데이터를 보냅니다.
(로컬 타이밍 중요도만 해당) FD_READ 가져오고 recv 를 호출하여 서버에서 보낸 응답 데이터를 가져옵니다. (4) 서버에 보낼 데이터가 더 이상 없음을 나타내기 위해 shutdown(s, SD_SEND)을 호출합니다.
(5) FD_CLOSE 표시를 받습니다. (로컬 타이밍 중요도만 해당) closesocket 를 호출합니다 .
(6) closesocket을 호출합니다.