前言
日常开发工作中,对于已经包含基础功能的系统,需要为前端同事提供测试环境时,常常需要在搭建好测试环境后,保证测试环境的正常运行,如果程序本身是控制台程序,那控制台就需要保证一直开启,关闭控制台程序将影响到测试系统的正常运行,相比于Linux
系的相关系统,例如Centos
、Ubuntu
,服务化便捷,同时支持也很多,例如Supervisor
,Windows
系统中,就显得比较尴尬,服务化手段较少,而且集中化管理较弱,测试系统演进如下:
- 人工通过控制台启动
服务重新部署需要退出控制台,部署后重新打开控制台 .bat
或.cmd
脚本启动
双击脚本(管理员或普通用户),测试系统就启动了,单个系统,单个程序启动忍一忍就过了,辅助的系统和程序一多,维护成本也会逐渐增加- 系统服务化启动
通过注册服务、启动服务、停止服务实现对系统启动细节的忽略,只关心系统的最终执行状态
sc.exe
简述
sc.exe
为服务控制管理service control manager
,用于对计算机的系统服务进行管理,实现注册,运行,暂停,自启等基础操作,用户能够将符合Windows
系统服务化条件的程序进行本地系统后台服务化运行,注册到服务注册表目录下的程序,通过sc
的指令实现程序执行状态的切换和管理。
指令清单
指令具体细节内容可以查看官网或笔者的另一篇文章太阳当空照-Windows服务化方式sc.exe指令清单
常用指令
sc create
添加服务信息到注册表中
sc <server> create [service name] [binPath= ] <option1> <option2>...
例如
>sc create sctest binPath= “\"E:\Study\Servers\sctest\sctest.exe\”"
sc description
设置服务的描述字符串
sc <server> description [service name] [description]
sc start
启动服务运行
sc <server> start [service name] <arg1> <arg2> ...
sc query
查询服务
sc query [service name] <arg1> <arg2> ...
sc stop
停止服务
sc stop [service name]
sc delete
删除服务注册表信息
sc delete [service name]
示例
服务案例
案例为笔者自己基于C#
,在基于Core3.1
创建的控制台程序,用于每隔一秒,项当前目录下的日志文件中换行写入小时:分钟:秒
,由于是使用符合Windows服务化标准的相关依赖库,此处略过对类库Microsoft.Extensions.Hosting.WindowsServices
的介绍和使用,项目源码可通过公众号进行领取,此处程序目前未为x86
,也可以依据需求生成x64
打包生成的文件结构如下:
创建服务
以管理员权限
运行cmd
,执行创建指令,binPath
=<空格>
尾部添加对应sctest.exe
的绝对路径,避免注册服务过程中,路径中的特殊字符无法被正常识别,可对路径外部添加双引号
sc create sctest binPath= “\"E:\Study\Servers\sctest\sctest.exe\”" [SC] CreateService 成功
查看任务管理器中的服务
打开服务
,找到sctest
服务,查看属性,会发现,binPath
实际就是可执行文件的路径
或者执行query
指令
>sc query sctest SERVICE_NAME: sctest TYPE : 10 WIN32_OWN_PROCESS STATE : 1 STOPPED WIN32_EXIT_CODE : 1077 (0x435) SERVICE_EXIT_CODE : 0 (0x0) CHECKPOINT : 0x0 WAIT_HINT : 0x0
添加描述
创建服务时,如果为通过指令sc create [service name] binPath= 路径 displayname= "描述内容"
,进行描述设置,可以通过,sc description
进行设置
>sc description sctest "this is sctestservice" [SC] ChangeServiceConfig2 成功
打开服务
查看sctest
的描述内容如下:
启动服务
方式一
直接使用sc start [service name]
进行服务启动,启动成功输出结果如下:
>sc start sctest SERVICE_NAME: sctest 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 : 32296 FLAGS :
方式二
也可以使用net start [service name]
进行服务启动
>net start sctest sctest 服务正在启动 . sctest 服务已经启动成功。
服务启动成功后,可以看到在sctest.exe
同一级别目录下,生成一个[年-月-日].log
文件,内容大体如下:
当前时间:Service Start 当前时间:00:29:50 当前时间:00:29:51 .........
停止服务
停止服务可以使用sc
,也可以使用net
,服务停止后,对应的[年-月-日].log
文件内容,也将不再增加
方式一
使用sc stop
,在使用sc query
查看服务当前状态,或直接去到任务管理器,查看任务页签中服务sctest
的状态
>sc stop sctest SERVICE_NAME: sctest TYPE : 10 WIN32_OWN_PROCESS STATE : 3 STOP_PENDING (STOPPABLE, NOT_PAUSABLE, ACCEPTS_SHUTDOWN) WIN32_EXIT_CODE : 0 (0x0) SERVICE_EXIT_CODE : 0 (0x0) CHECKPOINT : 0x0 WAIT_HINT : 0x0 >sc query sctest SERVICE_NAME: sctest TYPE : 10 WIN32_OWN_PROCESS STATE : 1 STOPPED WIN32_EXIT_CODE : 0 (0x0) SERVICE_EXIT_CODE : 0 (0x0) CHECKPOINT : 0x0 WAIT_HINT : 0x0
方式二
使用net stop
进行服务停止
>net stop sctest sctest 服务正在停止. sctest 服务已成功停止。
删除服务
使用指令sc delete
将对应服务进行删除
>sc delete sctest [SC] DeleteService 成功
关闭任务管理器再次打开,其中将不再能够看到服务sctest
,表明服务删除成功
常见问题
服务注册
binPath
服务程序执行路径
注册服务时,binPath
为必须项,需要指定路径,若是执行文件夹路径包含特殊字符时,需要为路径添加双引号如下:
sc create [service name] binPath= “服务程序绝对路径”
服务启动
启动失败,返回1503
服务注册成功后,启动服务时,服务等待一段时间后,返回程序无响应
[SC] StartService 失败 1053: 服务没有及时响应启动或控制请求。
查看Windows
自带的事件查看器
,在Windows日志
中系统
可以看到来源Service Control Manager
的相关错误信息
日志内容如下:
造成此类问题的情况很多,目前笔者摸索到的有以下几类:
- 目标程序本身,在编码级别,并没有通过编码方式,实现程序自身的
Windows服务化
,简单来说就是,程序不支持sc
方式启动 - 程序必要的程序启动路径,配置文件加载路径,内部数据输出路径等错误,造成程序执行异常
服务本身在启动时,默认为独立进程启动,实际上依据sc
的管理启动,程序的工作目录并不是在当前服务exe
所在目录,所以服务程序相关路径最好是以绝对路径方式配置,或者启动服务时参数传入,同时服务程序如果有对应的日志输出,也可以依据本地日志输出查看对应问题细节
服务删除
无法删除服务,提示服务已暂停
使用sc delete
删除对应服务时,提示该服务已暂停,此时需要关闭services.msc
,重新启动就可以发现,服务已经不存在
参考链接
【服务器角色命令】https://docs.microsoft.com/zh-cn/windows-server/administration/windows-commands/sc-config
【编写Windows服务】https://www.cnblogs.com/RainFate/p/12095793.html
获取上述内容中的服务测试源码项目,可关注私信或直接评论回复【sc.exe
】