Windows - 명령행에서 원격 서비스를 동기/비동기로 시작/중지
예전에도 설명했지만,
DOS batch - 동기 방식으로 원격 서비스 제어
; https://www.sysnet.pe.kr/2/0/989
net start/stop 명령어는 서비스를 동기 방식으로 시작/중지합니다. 하지만 net 명령어는 원격 서버의 서비스를 제어할 수는 없는데요, 그래서 sc 명령어를 사용할 수는 있지만 아쉽게도 그것은 비동기 방식으로만 가능합니다.
이에 대해 간단하게 go 언어로 작성한 서비스 예제로 실습해 보겠습니다.
Golang - 콘솔 응용 프로그램을 NT 서비스를 지원하도록 변경
; https://www.sysnet.pe.kr/2/0/13854
동기/비동기 서비스 제어를 차이가 느껴지도록 하기 위해 서비스 시작/중지 시에 시간을 8초 정도 지연하는 코드를 추가합니다.
func (m *myService) Execute(args []string, r <-chan svc.ChangeRequest, status chan<- svc.Status) (bool, uint32) {
const cmdsAccepted = svc.AcceptStop | svc.AcceptShutdown | svc.AcceptPauseAndContinue
time.Sleep(8 * time.Second)
log.Print("Starting service...!")
go doMyWork(false)
status <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}
loop:
for {
select {
case c := <-r:
switch c.Cmd {
case svc.Interrogate:
status <- c.CurrentStatus
case svc.Stop, svc.Shutdown:
log.Print("Shutting service...!")
break loop
case svc.Pause:
status <- svc.Status{State: svc.Paused, Accepts: cmdsAccepted}
case svc.Continue:
status <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}
default:
log.Printf("Unexpected service control request #%d\n", c)
}
}
}
status <- svc.Status{State: svc.StopPending}
time.Sleep(8 * time.Second)
status <- svc.Status{State: svc.Stopped}
return false, 1
}
자, 그럼 저걸 실습 PC 중 1대에 서비스로 등록 후,
// A 머신에서 실행
c:\temp> sc create go_sample binpath= "c:\temp\go_sample.exe" start= delayed-auto
또 다른 PC에서 아래와 같이 sc 명령어로 원격 서비스를 시작/중지 테스트를 해보면,
// B 머신에서 실행 (A 머신의 이름이 win2012r2라고 가정)
C:\temp> sc \\win2012r2 start go_sample
SERVICE_NAME: go_sample
TYPE : 10 WIN32_OWN_PROCESS
STATE : 2 START_PENDING
(NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x7d0
PID : 4828
FLAGS :
C:\temp> sc \\win2012r2 stop go_sample
SERVICE_NAME: go_sample
TYPE : 10 WIN32_OWN_PROCESS
STATE : 4 RUNNING
(STOPPABLE, PAUSABLE, ACCEPTS_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x0
8초의 대기 시간 없이 sc.exe는 제어를 곧바로 명령행 shell에 반환을 합니다. 즉, 비동기적으로 호출만 하고 결과를 대기하지 않는 것입니다. (물론, 억지로
서비스 상태가 "STOPPED"로 바뀔 때까지 대기하는 방법을 사용하는 것도 방법일 수 있습니다.)
만약
동기 방식으로 원격 서비스 제어를 원한다면 PowerShell로 대체할 수 있습니다.
// 서비스 중지
C:\temp> powershell "Get-Service -COMPUTER win2012r2 go_sample | Stop-Service"
// 서비스 시작
C:\temp> powershell "Get-Service -COMPUTER win2012r2 go_sample | Start-Service"
2개 모두 동기적으로 호출을 하기 때문에 8초 정도의 대기 시간이 발생하게 됩니다. 여기까지, 상황에 따라 정리해 보면 아래와 같습니다.
- net 명령어: 동기적 호출, 로컬 제어 O, 원격 제어 X
- sc 명령어: 비동기적 호출, 원격 서버 제어 가능
- PowerShell: 동기적 호출, 원격 서버 제어 가능
참고로, go 언어의 경우 Stop에 반응하는 부분에서 아래의 StopPending을 추가하지 않으면,
// status <- svc.Status{State: svc.StopPending}
time.Sleep(8 * time.Second)
status <- svc.Status{State: svc.Stopped}
해당 서비스를 중지 시 이런 오류가 발생합니다. (그래도 서비스 중지는 됩니다.)
Windows could not stop the go_sample service on Local Computer.
The service did not return an error. This could be an internal Windows error or an internal service error.
If the problem persists, contact your system administrator.
같은 8초 대기의 상황에서, 시작 시에는 굳이 StartPending을 추가하지 않아도 문제가 없는데, 중지 시에는 반드시 StopPending 단계를 거쳐야만 SCM과의 깔끔한 서비스 절차를 밟게 되는군요. ^^;
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]