新项目有一个服务需要作为windows服务运行在后台,并且需要守护。但是没有弄过windows的服务,找了一些资料,现记录一下备忘。
当做服务启动
并不是所有的可执行程序都可以作为服务启动,使用C语言或者C++开发的程序需要按照windows的服务开发规范,编译成可执行程序之后才能作为服务。
C#语言可以在Visual Studio上可以直接创建windows服务项目。
如果随便把一个程序创建成服务,会出现如下错误:

其实也有现成工具可以直接将一个可执行程序直接打包成服务,或者引入三方库也可以,但是总归是有依赖。
示例代码
#include <Windows.h>
#define SERVICE_NAME "ServiceTest"
SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE ServiceStatusHandle;
void WINAPI ServiceStatusHandler(DWORD control){
switch (control){
case SERVICE_CONTROL_STOP:
case SERVICE_CONTROL_SHUTDOWN:
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
break;
}
}
void WINAPI service_main(int argc, char ** argv){
ServiceStatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, ServiceStatusHandler);
if(ServiceStatusHandle == NULL){
return;
}
//
// user code here
//
ServiceStatus.dwServiceType = SERVICE_WIN32;
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_SHUTDOWN|SERVICE_ACCEPT_PAUSE_CONTINUE;
ServiceStatus.dwWin32ExitCode = NO_ERROR;
ServiceStatus.dwServiceSpecificExitCode = NO_ERROR;
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
}
int main(int argc, char ** argv){
SERVICE_TABLE_ENTRY serviceTable[2];
serviceTable[0].lpServiceName = SERVICE_NAME;
serviceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)service_main;
serviceTable[1].lpServiceName = NULL;
serviceTable[1].lpServiceProc = NULL;
StartServiceCtrlDispatcher(serviceTable);
return 0;
}
主要需要三个步骤:
StartServiceCtrlDispatcher注册服务入口,包含服务名称lpServiceName和服务启动入口lpServiceProc函数指针,注意参数是一个数组,而且数组一定要以NULL结尾;RegisterServiceCtrlHandler注册服务状态改变处理函数,主要处理服务的关闭、暂停、继续等状态操作。SetServiceStatus设置服务状态,比如运行中、停止、暂停等状态,需要手工设置,直接体现在windows的服务窗口上。
用户的业务初始化代码最好放在ServiceMain函数中,初始化完毕之后设置服务状态为运行中,服务才能启动成功。
作为服务运行
服务需要用到命令sc.exe,并且需要管理员权限。powershell找不到此命令。
创建服务
创建服务需要用到sc命令,简单创建一个服务命令如下:
sc create your-service-name binpath="your program path" start=auto
your-service-name是需要创建的服务的名称。binpath是关联的可执行程序的绝对路径,可以在路径后面添加参数,但是参数只能传递到main函数,不能到达ServiceMain,需要手动保存才可以。start指的是启动方式,可以是auto自动启动、demand手动启动、disable禁用等。
创建成功之后,运行win+R,输入services.msc,打开之后就可以找到你创建的服务,如果一切正常就可以启动成功了。
启动命令:
sc start your-service-name
开启服务守护
如果程序崩溃,服务可以自动启动。右键你的服务,然后在恢复标签里面选择第一次失败、第二次失败和后续失败后的行为,如果只是需要在程序崩溃后重新启动,选择重新启动程序即可。下面可以设置失败后多久后重启,设置0分钟会在程序奔溃后立即重启。
也可以在命令行中设置服务守护,输入如下命令:
sc failure your-service-name reset=0 actions=restart/3000/restart/3000/restart/3000
reset是失败多少次后重置失败次数。actions后面的三个restart分别是第一次失败、第二次失败和后续失败后的行为,除了restart还可以是run或者reboot,后面的数字是执行时间ms。使用命令设置的时间粒度比设置界面上更细。
注意actions需要和reset一起使用,具体说明见官方文档:sc failure.
删除服务
执行一下命令即可:
sc delete your-service-name
Ref
https://blog.csdn.net/chenyujing1234/article/details/8023816