什麼是windows服務
Windows 服務是主要用於服務器環境而長期運行的應用程序, 這類程序不需要有用戶界面或者任何模擬輸出。 任何的用戶消息通常都是記錄在Windows 事件日誌裏。Windows Service可以在操作系統啓動的時候開始,一直在後臺運行,當有需要時也可以手動啓動,我們可以通過管理工具裏面的服務進行統一管理。
當系統啓動完畢後,Windows服務並不需要通過登陸頁面後才能啓動,即使用戶註銷登錄也不會停止,通常不和用戶產生交互。
而我們啓動一般的exe文件卻要先登陸Windows後才能啓動它,通常還有一個用戶界面,命令行或者是GUI界面,通常由用戶手動啓動和停止。
如何註冊windows服務
手工註冊Windows服務得用得到windows下cmd命令(管理員身份)
註冊服務 [ServiceTest]:
sc create ServiceTest binpath="/path/to/exe"
啓動服務:
sc start ServiceTest
停止服務、刪除服務:
sc stop ServiceTest
sc delete ServiceTest
用vc++實現windows服務:
首先要初始化 SERVICE_TABLE_ENTRY 結構體數組,
SERVICE_TABLE_ENTRY serviceEntryTable[2];
serviceEntryTable[0].lpServiceName = L"ServiceTest";
serviceEntryTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceWorker;
serviceEntryTable[1].lpServiceName = NULL;
serviceEntryTable[1].lpServiceProc = NULL;
其中,ServiceTest 是要註冊的服務的名稱,ServiceWorker 是服務主工作函數。
通過調用 StartServiceCtrlDispatcher(serviceEntryTable)
,把調用進程的主線程轉換爲控制分派器,啓動一個新線程運行分派表中的 ServiceWorker 函數。
然後,準備ServiceWorker函數,
ServiceWorker 服務程序的主運行函數,除了與普通函數執行任務之外,
它還需要完成一個工作:通過調用 RegisterServiceCtrlHandler
向服務控制管理器註冊控制函數。
並且調用 向 SCM(服務控制管理器)報告當前的狀態。
SERVICE_STATUS serviceStatus;
serviceStatus.dwServiceType = SERVICE_WIN32;
serviceStatus.dwCurrentState = SERVICE_START_PENDING;
serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP;
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwServiceSpecificExitCode = 0;
serviceStatus.dwCheckPoint = 0;
serviceStatus.dwWaitHint = 0;
serviceStatusHandle = ::RegisterServiceCtrlHandler(L"ServiceTest", ServiceCtrlHandler);
其中 ServiceCtrlHandler
是控制處理函數,它接收 SCM 發來的控制命令,並且處理命令和回饋狀態。
最後,準備控制處理函數 ServiceCtrlHandler
控制處理函數必須在30秒內返回,否則 SCM 會返回一個錯,如果是一個比較耗時的操作,則需要另啓一個線程來進行處理。
void WINAPI ServiceCtrlHandler(DWORD request)
{
switch (request)
{
case SERVICE_CONTROL_STOP:
serviceRunning = false;
serviceStatus.dwCurrentState = SERVICE_STOPPED;
break;
case SERVICE_CONTROL_SHUTDOWN:
serviceRunning = false;
serviceStatus.dwCurrentState = SERVICE_STOPPED;
break;
default:
break;
}
SetServiceStatus(serviceStatusHandle, &serviceStatus);
}
完整示例代碼
該示例實現了一個簡單的windows服務程序,
每秒鐘在C盤目錄下打印一個數字。
#include <string>
#include <fstream>
#include <iostream>
#include <windows.h>
using namespace std;
bool serviceRunning = false;
SERVICE_STATUS serviceStatus;
SERVICE_STATUS_HANDLE serviceStatusHandle;
void WINAPI ServiceWorker(int argc, char** argv);
void WINAPI ServiceCtrlHandler(DWORD request);
void ServiceLog(string str)
{
fstream fout("c:/service_log.txt", ios::out | ios::app);
if (!fout) {
return;
}
fout << str << endl;
}
void WINAPI ServiceWorker(int argc, char** argv)
{
serviceStatus.dwServiceType = SERVICE_WIN32;
serviceStatus.dwCurrentState = SERVICE_START_PENDING;
serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP;
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwServiceSpecificExitCode = 0;
serviceStatus.dwCheckPoint = 0;
serviceStatus.dwWaitHint = 0;
serviceStatusHandle = ::RegisterServiceCtrlHandler(L"ServiceTest", ServiceCtrlHandler);
if (0 == serviceStatusHandle)
{
ServiceLog("RegisterServiceCtrlHandler failed");
return;
}
ServiceLog("RegisterServiceCtrlHandler success");
serviceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus(serviceStatusHandle, &serviceStatus);
// 工作內容,每隔一秒鐘輸出一個數字
int num = 0;
serviceRunning = true;
while (serviceRunning)
{
ServiceLog(to_string(num++));
Sleep(1000);
}
ServiceLog("Service Stopped");
}
void WINAPI ServiceCtrlHandler(DWORD request)
{
switch (request)
{
case SERVICE_CONTROL_STOP:
serviceRunning = false;
serviceStatus.dwCurrentState = SERVICE_STOPPED;
break;
case SERVICE_CONTROL_SHUTDOWN:
serviceRunning = false;
serviceStatus.dwCurrentState = SERVICE_STOPPED;
break;
default:
break;
}
SetServiceStatus(serviceStatusHandle, &serviceStatus);
}
void main()
{
SERVICE_TABLE_ENTRY serviceEntryTable[2];
serviceEntryTable[0].lpServiceName = L"ServiceTest";
serviceEntryTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceWorker;
serviceEntryTable[1].lpServiceName = NULL;
serviceEntryTable[1].lpServiceProc = NULL;
StartServiceCtrlDispatcher(serviceEntryTable);
}
Golang 實現 Windows 服務
Go語言有第三方封裝好的庫,可以用很少的代碼實現一個Windows服務,相比C++方便了很多。
package main
import (
"log"
"os"
"time"
"github.com/kardianos/service"
)
type program struct{}
func (p *program) Start(s service.Service) error {
go p.run()
return nil
}
func (p *program) run() {
for {
time.Sleep(time.Second)
log.Println("running")
}
}
func (p *program) Stop(s service.Service) error {
return nil
}
func init() {
f, err := os.Create("d:/gowinservice.txt")
if err != nil {
log.Fatal(err)
}
log.SetOutput(f)
}
func main() {
svcConfig := &service.Config{
Name: "GoService",
DisplayName: "GoServiceDis",
Description: "windows service form golang",
}
prg := &program{}
s, err := service.New(prg, svcConfig)
if err != nil {
log.Fatal(err)
}
if len(os.Args) > 1 {
if os.Args[1] == "install" {
s.Install()
log.Println("服務安裝成功")
return
}
if os.Args[1] == "remove" {
s.Uninstall()
log.Println("服務卸載成功")
return
}
}
if err = s.Run(); err != nil {
log.Fatal(err)
}
}