인프런 커뮤니티 질문&답변

RYLYNN님의 프로필 이미지

작성한 질문수

Windows 소켓 프로그래밍 입문에서 고성능 서버까지!

ThreadAcceptLoop 의 우아한(?) 종료에 대해 질문드립니다.

해결된 질문

24.08.11 12:18 작성

·

89

0

안녕하십니까, TCP/IP, IOCP 개념을 배우는데 강사님의 강의가 큰 도움이 되었습니다.

다름이 아니라, IOCP 코드를 C++ Class 로 작성중에 소멸자에서 리소스들을 해제 하려고 작성 중에 있는데 ThreadAcceptLoop 스레드를 우아하게 종료하기 위한 방법이 있는지 궁금하여 질문을 하나 드려봅니다.

 

g_hSocket : Server Listen Socket

DWORD WINAPI ThreadAcceptLoop(LPVOID pParam)

while ((hClient = ::accept(g_hSocket,

&ClientAddr, &nAddrSize)) != INVALID_SOCKET)

{

// Do Something...

}

보시다싶이 ThreadAcceptLoop 함수 내부에서 ::accept() 를 처리해주고 있고 accept 에 들어가는 순간 Blocking 이 되어버립니다.

저는 스레드의 완전 종료를 위해 accept 함수를 빠져나가기 위한 방법을 찾아보니 g_hSocket = NULL 또는 INVALID_SOCKET 을 할당 해주는것 말고는 Accept 함수를 빠져나갈 수 있는 방법이 없는 것 처럼 보이더라구요.

 

하지만 이런식으로 NULL 할당하여 accept 를 빠져나가도록 하고 WSAGetLastError 를 호출해보면 "WSACancelBlockingCall를 호출하여 차단 작업이 중단되었습니다." 라는 에러를 확인할 수 있었습니다.

 

g_hSocket = NULL 호출 후 해당 오류를 무시해도 지나가도 되는 코드인지, 아니면 accept Blocking 상태를 빠져나가기 위한 "우아한 방법" 이 있는지 궁금합니다.

 

현재 작성한 코드 순서는 아래와 같습니다. 스레드는 _beginthreadex 로 호출해서 핸들을 가지고 있습니다.

::shutdown(g_hSocket, SD_BOTH);

if (g_hSocket!= INVALID_SOCKET)

{

::closesocket(g_hSocket);

g_hSocket= INVALID_SOCKET; // 이 시점에 accept blocking 이 풀린다!

}

// Accept Thread 종료를 대기하자

WaitForSingleObject(IOCPAcceptThreadHandle._threadHandle, INFINITE);

CloseHandle(IOCPAcceptThreadHandle._threadHandle);

 

감사합니다.

 

답변 2

0

널널한 개발자님의 프로필 이미지
널널한 개발자
지식공유자

2024. 08. 15. 15:16

인프런 AI의 답변을 참고하시면 되겠습니다.

접속 대기 중인 서버 소켓을 다른 스레드에서 닫아버리면 accept() 함수가 반환합니다. 이를 통해 자연스럽게 종료 시킬 수 있습니다. 참고하시기 바랍니다. 😃

0

인프런 AI 인턴님의 프로필 이미지

2024. 08. 13. 12:21

안녕하세요, 인프런 AI 인턴입니다.

RYLYNN님, TCP/IP와 IOCP에 관한 질문에 대해 답변 드리겠습니다.

코드를 통한 스레드 종료 방법을 찾으시는 군요. 그리고 ThreadAcceptLoop의 우아한 종료 방법에 대해 궁금해 하신 것으로 보입니다.

스레드의 우아한 종료를 위해서는 스레드가 실행 중인 작업을 안전하게 마무리하고 자원을 해제하는 과정이 중요합니다. RYLYNN님이 제시한 코드 순서는 이미 이러한 과정을 반영하고 있습니다.

::shutdown(g_hSocket, SD_BOTH); 호출을 통해 소켓의 양방향 통신을 종료시키고, 이후 ::closesocket(g_hSocket);를 호출하여 소켓을 닫는 것은 우아한 리소스 해제 방법입니다. 다만, g_hSocket = NULL 대신에 g_hSocket = INVALID_SOCKET; 을 사용하는 것이 좋습니다. g_hSocketNULL로 설정하는 대신 INVALID_SOCKET으로 설정하는 것이 더 명확한 의미를 가지며, 일반적으로 소켓 프로그래밍에서 소켓이 유효하지 않음을 나타내는 방식입니다.

accept 함수의 블로킹 상태를 해제하기 위해 shutdownclosesocket을 호출한 후, 스레드를 종료하기 위해 WaitForSingleObject 함수를 사용한 대기와 CloseHandle을 호출한 것까지, 전반적으로 RYLYNN님의 접근 방식은 적절합니다.

WSACancelBlockingCall 오류는 accept 함수가 블로킹 상태에서 해제될 때 발생할 수 있는데, 이 경우 일반적으로 스레드 종료를 위해 의도된 동작이므로 크게 문제되지 않습니다.

요약하자면, RYLYNN님의 코드는 이미 스레드의 우아한 종료를 위한 적절한 접근 방식을 따르고 있습니다. 블로킹 상태를 해제하고 소켓을 닫는 과정에서 발생하는 오류 메시지는 이 상황에서 예상되는 정상적인 동작이며, 이를 통해 스레드를 안전하게 종료할 수 있습니다.

추가적으로 관련된 내용은 Spring Boot의 문서에도 유사한 컨셉인 “우아한 종료”에 대해 다루고 있으나, 직접적인 소켓 프로그래밍과는 차이가 있기 때문에, 구체적인 C++ 소켓 프로그래밍 혹은 윈도우 소켓 API 관련 문서를 참고하는 것이 더 도움이 될 것입니다.

질문에 대해 충분한 답변이 되었기를 바랍니다. 추가적인 질문이 있으시면 언제든지 문의해주세요.

RYLYNN님의 프로필 이미지

작성한 질문수

질문하기