이번 장에서는 서비스의 몸통을 만들기 전에 서비스를 인스톨 하는 부분과 제거하는 부분에 대하여 알아볼 것이다.
서비스를 설계할 때 기능도 당연히 중요하지만 어떤 동작 상태를 주어 기동하게 할것인가에 대하여 생각해 보아야한다.
1. 먼저 서비스 이름이나 설명을 어떻게 설정할 것인가?
-> 단순한 문제이지만, 서비스 이름이나 실행파일명, 그리고 이에 따른 설명은 해당 서비스가 어떠한 기능을 하게 되는지
그리고, 사용하는 사람들이 직관적으로 알아 볼 수 있도록 명확하게 하여야 한다.
2. 서비스를 구동 시키는 계정은 어떻게 처리할 것인가?
-> 보통 아주 일반적으로 디폴트 계정 즉, SYSTEM(Local System Account) 계정을 사용하게 된다.
아주 일반 적인 상황이지만, 간혹 Administrator 계정으로 설정해야 하거나, 혹은 특정 Users 계정으로 구동해야 하는
경우도 없지않다.
SYSTEM 계정이 아닌 다른 계정을 사용하게 되면 해당 계정에 SeServiceLogonRight 권한을 주어야한다.
또한 암호가 비어있는 유저일 경우는 이것 외에도 보안 설정을 풀어주어야 한다.
3. 초기 구동시 자동 시작으로 할것인가? 수동 시작으로 할것인가?
-> 보통 자동시작으로 초기 설정을 확정하는 경우가 많은데... 서비스가 순수하게 독립 기능을 수행할 경우는 모르겠지만
먼가 연계되는 부분이 존재한다면, 사용자가 시작 시켜주기를 기다려야 할 수도 있다.
이러한 상황을 무시하고 무조껀 자동 시작으로 해놓으면, 서비스가 구동에 실패하면서 시스템 로그에 서비스 구동 실패
로그를 쌓을 것이다.
4. 서비스가 구동에 실패하였을 경우, 어떠한 처리를 할것인가?
-> 보통 정상적으로 서비스가 구동되기를 기대하지만, 아주 황당한 이유등으로 서비스 구동이 실패할 수 있다.
주로 겪는 문제가 Network Adapter 장애로 인하여 소켓등에 문제가 생기거나, 과부하로 인해 스토리지가 깨지거나
AD 서버 장애로 인하여 로그인에 실패하거나 DBMS가 죽어 있거나 .... 등등.. 여러가지 문제가 발생할 수 있다.
5. 특정 서비스에 의존하는 부분이 존재하는가?
-> 특수 목적용으로 만들어진 서비스중에서는 DBMS에 의존하던가? 무선랜 서비스가 켜져 있어야 한다던가?
원격의 관리를 위하여 여러 서비스가 활성화 되어 있어야 한다건가..
편하게 이러한 시스템 에러에 대응하여 디펜던시를 걸어 놓으면 가장 편하게 에러 상황을 피해 나갈 수 있다.
문제는 이렇게 디펜던시를 걸어 놓으면 상위 서비스에 장애가 생겼을 경우, 하위 서비스는 아예 구동 조차도
되지 않으므로 어떠한 문제가 발생하였는지 전혀 알 수 가 없다는 것이다.
그래서, 디펜던시를 걸어 놓는 방법은 추천하지 않는다. 특정 서비스에 종속적이라면 서비스가 초기 구동될 때
해당 서비스들의 구동 상태를 점검하고 꺼져 있는건 시작 시켜주고 문제가 생기면 에러 로깅을 해주고 종료해야 한다.
6. 데스크탑 유저들과 연동해야 하는 부분이 존재하는가?
-> 서비스는 백그라운드에서 구동되기 때문에 사실상 로그온된 상태의 유저들에게 화면상으로 정보를 전달하는게 불가능하다.
보통 IPC를 통하여 사용자 프로그램과 연동하지만, 서비스에서 GUI 어플리케이션을 실행 시켜 줄 수도 있다.
데스크탑과 연동이라는 옵션을 이용하면, 이러한 부분을 일부 커버할 수 있지만, 이건 순수하게 Console Session 만 해당한다.
즉, 터미널 유저에게는 영향을 못미친다는 것이다.
서비스와 연동하는 GUI에서 특정 정보를 전달하고 종료했을 때, 서비스 구동에 문제가 생기면 로그에만 남겨야할까?
머 저렇게 하나씩 준비해서 서비스의 설치단계를 진행하는 사람은 없겠지만, 한번 쯤은 점검해볼 필요는 있지 않을까?
사실상 개발할 때 문제가 되거나 가장 귀찬은 영역이 4, 5, 6 번 영역이다... -_-;;;
다음의 예제 코드는 아주 간단한 서비스 설치 코드이다. 설정을 최소화한 상태에서는 저렇게 쉬울 수가 없다.
서비스를 설계할 때 기능도 당연히 중요하지만 어떤 동작 상태를 주어 기동하게 할것인가에 대하여 생각해 보아야한다.
1. 먼저 서비스 이름이나 설명을 어떻게 설정할 것인가?
-> 단순한 문제이지만, 서비스 이름이나 실행파일명, 그리고 이에 따른 설명은 해당 서비스가 어떠한 기능을 하게 되는지
그리고, 사용하는 사람들이 직관적으로 알아 볼 수 있도록 명확하게 하여야 한다.
2. 서비스를 구동 시키는 계정은 어떻게 처리할 것인가?
-> 보통 아주 일반적으로 디폴트 계정 즉, SYSTEM(Local System Account) 계정을 사용하게 된다.
아주 일반 적인 상황이지만, 간혹 Administrator 계정으로 설정해야 하거나, 혹은 특정 Users 계정으로 구동해야 하는
경우도 없지않다.
SYSTEM 계정이 아닌 다른 계정을 사용하게 되면 해당 계정에 SeServiceLogonRight 권한을 주어야한다.
또한 암호가 비어있는 유저일 경우는 이것 외에도 보안 설정을 풀어주어야 한다.
3. 초기 구동시 자동 시작으로 할것인가? 수동 시작으로 할것인가?
-> 보통 자동시작으로 초기 설정을 확정하는 경우가 많은데... 서비스가 순수하게 독립 기능을 수행할 경우는 모르겠지만
먼가 연계되는 부분이 존재한다면, 사용자가 시작 시켜주기를 기다려야 할 수도 있다.
이러한 상황을 무시하고 무조껀 자동 시작으로 해놓으면, 서비스가 구동에 실패하면서 시스템 로그에 서비스 구동 실패
로그를 쌓을 것이다.
4. 서비스가 구동에 실패하였을 경우, 어떠한 처리를 할것인가?
-> 보통 정상적으로 서비스가 구동되기를 기대하지만, 아주 황당한 이유등으로 서비스 구동이 실패할 수 있다.
주로 겪는 문제가 Network Adapter 장애로 인하여 소켓등에 문제가 생기거나, 과부하로 인해 스토리지가 깨지거나
AD 서버 장애로 인하여 로그인에 실패하거나 DBMS가 죽어 있거나 .... 등등.. 여러가지 문제가 발생할 수 있다.
5. 특정 서비스에 의존하는 부분이 존재하는가?
-> 특수 목적용으로 만들어진 서비스중에서는 DBMS에 의존하던가? 무선랜 서비스가 켜져 있어야 한다던가?
원격의 관리를 위하여 여러 서비스가 활성화 되어 있어야 한다건가..
편하게 이러한 시스템 에러에 대응하여 디펜던시를 걸어 놓으면 가장 편하게 에러 상황을 피해 나갈 수 있다.
문제는 이렇게 디펜던시를 걸어 놓으면 상위 서비스에 장애가 생겼을 경우, 하위 서비스는 아예 구동 조차도
되지 않으므로 어떠한 문제가 발생하였는지 전혀 알 수 가 없다는 것이다.
그래서, 디펜던시를 걸어 놓는 방법은 추천하지 않는다. 특정 서비스에 종속적이라면 서비스가 초기 구동될 때
해당 서비스들의 구동 상태를 점검하고 꺼져 있는건 시작 시켜주고 문제가 생기면 에러 로깅을 해주고 종료해야 한다.
6. 데스크탑 유저들과 연동해야 하는 부분이 존재하는가?
-> 서비스는 백그라운드에서 구동되기 때문에 사실상 로그온된 상태의 유저들에게 화면상으로 정보를 전달하는게 불가능하다.
보통 IPC를 통하여 사용자 프로그램과 연동하지만, 서비스에서 GUI 어플리케이션을 실행 시켜 줄 수도 있다.
데스크탑과 연동이라는 옵션을 이용하면, 이러한 부분을 일부 커버할 수 있지만, 이건 순수하게 Console Session 만 해당한다.
즉, 터미널 유저에게는 영향을 못미친다는 것이다.
서비스와 연동하는 GUI에서 특정 정보를 전달하고 종료했을 때, 서비스 구동에 문제가 생기면 로그에만 남겨야할까?
머 저렇게 하나씩 준비해서 서비스의 설치단계를 진행하는 사람은 없겠지만, 한번 쯤은 점검해볼 필요는 있지 않을까?
사실상 개발할 때 문제가 되거나 가장 귀찬은 영역이 4, 5, 6 번 영역이다... -_-;;;
다음의 예제 코드는 아주 간단한 서비스 설치 코드이다. 설정을 최소화한 상태에서는 저렇게 쉬울 수가 없다.
SC_HANDLE hScm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (hScm == NULL)
return GetLastError();
SC_HANDLE hSrv = CreateService(
hScm,
"서비스의 고유 이름",
"서비스의 외부 표시 이름",
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START,
SERVICE_ERROR_NORMAL,
"서비스 실행파일 경로",
NULL, NULL, NULL, NULL, NULL);
if(hSrv )
CloseServiceHandle(hSrv);
CloseServiceHandle(hScm);
if (hScm == NULL)
return GetLastError();
SC_HANDLE hSrv = CreateService(
hScm,
"서비스의 고유 이름",
"서비스의 외부 표시 이름",
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START,
SERVICE_ERROR_NORMAL,
"서비스 실행파일 경로",
NULL, NULL, NULL, NULL, NULL);
if(hSrv )
CloseServiceHandle(hSrv);
CloseServiceHandle(hScm);
자, 아주 쉽게 서비스의 설치가 완료되었다. 간단하게 이름을 주고, 자동시작하고, 에러는 적당히 시스템로그에 남기고 끝이다.
보통 대부분의 서비스의 설치는 저 상태라도 전혀 문제가 없다...
1. 시스템을 관리하기 위하여 특정한 SP_USER 라는게 생성되었다. 모든 동작이 해당 계정에서 처리되며, 각종 레지스트리도 저 유저 계정하에서
동작되도록 처리해야 한다. 해당 계정으로 만들어진 대부분은 Administrator 의 접근을 배제 시켜 놓았다.
작업의 편의성을 위해서라도 서비스의 구동 계정을 SP_USER 라고 맞출 필요가 방금 생긴것이다. 왜? 방금 생각해 낸것이니까 ㅡ.,ㅡ
그렇다면 SP_USER가 암호를 가지고 있는가? 아닌가에 따라 작업이 또 달라진다.
SP_USER 가 암호를 가진 유저라면 해당 계정에 SeServiceLogonRight 권한만 주면 문제가 없겠지만, 아쉽게도 암호가 비어있을 경우는
또다른 문제를 생성시킨다. 즉, 기본적으로 서비스를 구동시키는 계정은 암호를 비워둘 수가 없다.
그냥 서비스 계정을 SYSTEM 으로 만들면 아주 편한데, 저거 하나 때문에 골머리 썩어보신 분이 있을 겄이다. (없으면 나만 그랬나.. ㅡㅜ);
(물론 서비스 매니저에서 마우스로 클릭해주고, 보안 관리자에서 보안을 손으로 풀어주면 아주 쉽게 해결되는 부분이기도 하다. 아주 아주 쉽다...)
(항상 코딩으로 먼가를 해결해야 할때가 문제인거다 -_-;;;)
서비스 설치에 저런게 있다는거고 모두 저런 자질구래한 것에 신경 쓸 필요는 없다. 필요한 사람에게 아주 가끔 도움이 될 수 있을까?
세세한 설치방법과 에러 처리에 관한 부분은 샘플 코드를 작성하는 부분으로 넘긴다.
자 다음으로는 서비스를 제거해봐야 겠다.
SC_HANDLE hScm = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
if (hScm == NULL)
return GetLastError();
SC_HANDLE hSrv = OpenService(hScm, "서비스 이름", SERVICE_ALL_ACCESS);
if (hSrv == NULL)
goto ERROR_LABEL;
if(!DeleteService(hSrv))
goto ERROR_LABEL;
ERROR_LABEL:
if(hSrv)
CloseServiceHandle(hSrv);
if(hScm)
CloseServiceHandle(hScm);
if (hScm == NULL)
return GetLastError();
SC_HANDLE hSrv = OpenService(hScm, "서비스 이름", SERVICE_ALL_ACCESS);
if (hSrv == NULL)
goto ERROR_LABEL;
if(!DeleteService(hSrv))
goto ERROR_LABEL;
ERROR_LABEL:
if(hSrv)
CloseServiceHandle(hSrv);
if(hScm)
CloseServiceHandle(hScm);
별도의 에러처리는 실제 프로그램을 하면서 하나씩 진행하면 되므로, 특별한 에러처리나 이런것은 배제하였다.
다음으로는 여기서 중간 중간 설명하던 권한이나, 서비스 상태에서 데스크탑에 GUI를 띄워주거나 이런 잘잘한 기능을 구현한 함수들을
일부 소개한다. 앞으로 가끔 쓰일것이므로, 미리 포스팅하여 참고할 수 있도록 할것이다.