2. ServiceMain
과 서비스 제어 처리자(ServiceCtrlHandler)
윈도우즈 NT 서비스프로그램은 WinMain()
이외에 2개의
다른
함수를
윈도우에 export 하여야
한다. 그중
하나가 ServiceMain()
함수로서
이
이름은
고정된
것이
아니다. 지난
강좌에서
보았던 WinMain()
함수의
제일
마지막
부분에
서비스
제어자로서
등록하는
부분이
있는
데
이때 ServiceMain()
함수의
이름을
서비스
제어
관리자(SCM-Service Control
Manager)에
등록한다.
SERVICE_TABLE_ENTRY DispatchTable[] = { {
ECHOSVC_NAME, ServiceMain }, { 0, 0 }
};
if ( argc < 2 )
{
if ( !StartServiceCtrlDispatcher(DispatchTable) )
{
DbgOut("EchoServer :
StartServiceCtrlDispatcher error = %d\n", GetLastError() );
}
}
서비스
제어
관리자(SCM)에
의해
시작된
서비스
프로그램은 ServiceMain()
함수를
실행하게
되는
데, 이때
서비스
메인에서
해야할
일은
크게 2가지
이다.
- 서비스
제어
처리자(Service Control
Handler)를
등록한다.
- while 루프를
사용하여
서비스
프로그램의
실행을
유지한다.
서비스
제어
처리자는
서비스
제어
관리자에
의해
서비스
실행에
대한
변화가
생겼을
때
처리를
하는
루틴이다. 예를
들어
누군가가
서비스의
실행을
중지
시킨다면
서비스
관리자는SERVICE_CONTROL_STOP
코드를
서비스
제어
처리자에
보내
서비스
프로그램으로
하여금
서비스를
종료하게
한다.
물론
이러한
요청은
지난
강좌에서
필자의 LXSVC 클래스의 SCM 제어
함수에
의한
프로그래밍
방법으로도
가능하며
또는
사용자가
제어판->관리자툴->서비스
프로그램을
통해서도
가능하다.
서비스
제어
처리자를
등록하는
것은
아래와
같이
간단한
함수
호출로
이루어진다.
SERVICE_STATUS_HANDLE
ServiceStatusHandle = RegisterServiceCtrlHandler( ECHOSVC_NAME,
ServiceCtrlHandler );
if ( ServiceStatusHandle ==
(SERVICE_STATUS_HANDLE) 0 )
{
DbgOut("EchoServer :
RegisterServiceCtrlHandler() failed %d\n", GetLastError() );
return;
}
서비스
메인
함수의
두번째
할
일인 while 루프를
사용하여
서비스
프로그램의
실행을
유지하는
것은
반드시
필요한
것은
아니다. 예를
들어
서비스가
시스템
시작시에만
잠깐
실행되어도
된다면
굳이
실행을
유지할
이유는
없다. 다만
본래
서비스의
정의
자체가
운영체제의
일부로서
운영체제를
지원하는
것임을
생각할
때, 서비스의
실행이
시스템
종료까지
유지되는
것이
바람직하다는
것이
일반적인
서비스
프로그램의
모습일
것이다.
필자의
예에선g_isRunning
라는 boolean
변수를
두어
이
변수가
참인
동안 while 루프를
반복하게
하였다. 이
변수는
서비스
제어
처리자에SERVICE_CONTROL_STOP
코드가
넘어오면
거짓이
되어 ServiceMain()
함수를
종료하게
된다.
bool g_isRunning = false;
g_isRunning = true;
while (g_isRunning)
{
DbgOut("EchoServer : Service
running...\n");\
Sleep(1000);
}
서비스
제어
처리자(Service Control
Handler)는
앞서
밝혔듯이
서비스
제어
관리자(SCM)가
보내는
제어
코드를
처리하는
함수이며 ServiceMain()
함수에
의해
등록이
된다. 서비스
제어
처리자가
받는
가장
일반적인
제어
코드는SERVICE_CONTROL_PAUSE,
SERVICE_CONTROL_CONTINUE, SERVICE_CONTROL_STOP이며
필자의
예제
함수에
보듯이
처리
상황은
상당히
단순하다.
VOID WINAPI ServiceCtrlHandler(DWORD
dwControl)
{
DbgOut("EchoServer :
ServiceCtrlHandler\n");
switch(dwControl)
{
case SERVICE_CONTROL_PAUSE:
DbgOut(" -
SERVICE_CONTROL_PAUSE\n");
g_lxSvc->SetServiceStatus(SERVICE_PAUSED);
break;
case SERVICE_CONTROL_CONTINUE:
DbgOut(" -
SERVICE_CONTROL_CONTINUE\n");
g_lxSvc->SetServiceStatus(SERVICE_RUNNING);
break;
case SERVICE_CONTROL_STOP:
DbgOut(" -
SERVICE_CONTROL_STOP\n");
g_isRunning =
false;
g_lxSvc->SetServiceStatus(SERVICE_STOPPED);
break;
case SERVICE_CONTROL_INTERROGATE:
DbgOut(" -
SERVICE_CONTROL_INTERROGATE\n");
break;
default:
DbgOut("EchoServer : unrecognized control
code %ld\n", dwControl );
}
return;
}
그러나
서비스
상태를
지정해
주는
것은 어렵진 않지만 서비스
상태
값의
잘
못된
지정에
의해
실제
프로그래밍
시에
상당한
곤란을
겪을
수도
있다. 여기서
자세히
다룰
필요는
없다고
생각되며
자세한
것은 LXSVC 클래스의SetServiceStatus() 멤버함수를
참조하기
바란다.
이것으로서
대략적인
서비스
프로그램의
윤곽은
살펴보았다고
할
수
있다. 윈도우즈
프로그램이
기본적으로
따르는
모양(WinMain()
과 WndProc()
함수로
구성되는
모양)이
있듯이
서비스
프로그램
역시
기본적인
모양이
있다. 이
글을
읽는
독자들은
서비스
프로그램을
작성해야
할
일이
있을
때
기본
프로그램
틀로서
필자의
예제를
가져다
놓고
시작하면
좋을
것이다.
다음
강좌에서는
실제로
윈속을
다루는
클래스를
보이고자
한다.
- Reference
http://cafe.naver.com/nevernding
'[ Windows Program ] > Windows API' 카테고리의 다른 글
멀티쓰레드 윈도우즈 소켓 프로그래밍 #5– 멀티쓰레드 프로그래밍 2 (0) | 2011.03.08 |
---|---|
멀티쓰레드 윈도우즈 소켓 프로그래밍 #4 – 멀티쓰레드 프로그래밍 (0) | 2011.03.08 |
멀티쓰레드 윈도우즈 소켓 프로그래밍 #2 – 윈도우즈 서비스 프로그래밍 (2) | 2011.03.08 |
멀티쓰레드 윈도우즈 소켓 프로그래밍 #1 (0) | 2011.03.08 |
비동기소켓 서버구현 (0) | 2011.03.07 |