Windows 服务应用程序介绍 | Microsoft Docs https://docs.microsoft.com/zh-cn/dotnet/framework/windows-services/introduction-to-windows-service-applications
Microsoft Windows 服务(过去称为 NT 服务)允许用户创建可在其自身的 Windows 会话中长时间运行的可执行应用程序。 这些服务可在计算机启动时自动启动,可以暂停和重启,并且不显示任何用户界面。 这些功能使服务非常适合在服务器上使用,或者需要长时间运行的功能(不会影响在同一台计算机上工作的其他用户)的情况。 还可以在与登录用户或默认计算机帐户不同的特定用户帐户的安全性上下文中运行服务。 有关服务和 Windows 会话的详细信息,请参阅 Windows SDK 文档。
可以通过创建作为服务安装的应用程序来轻松创建服务。 例如,假设你想监视性能计数器数据并对阈值作出响应。 可以编写一个侦听性能计数器数据的 Windows 服务应用程序,部署该应用程序并开始收集和分析数据。
可以将服务创建为 Microsoft Visual Studio 项目,并在其中定义代码,以控制可以将哪些命令发送到服务以及在收到这些命令时应采取的操作。 可以发送到服务的命令包括启动、暂停、恢复和停止服务,还可以执行自定义命令。
在创建和生成应用程序之后,可以通过运行命令行实用程序 InstallUtil.exe 并将该路径传递给服务的可执行文件来安装它。 然后,可以使用服务控制管理器 来启动、停止、暂停、恢复和配置服务。 还可以在“服务器资源管理器” 的“服务” 节点中或使用 ServiceController 类完成许多相同的任务。
服务应用程序与其他 Visual Studio 应用程序
服务应用程序与许多其他项目类型的运行方式存在以下几个方面的不同:
-
在项目能够以有意义的方式运行之前,服务应用程序项目创建的已编译可执行文件必须安装在服务器上。 无法通过按 F5 或 F11 来调试或运行服务应用程序;无法立即运行服务或单步执行其代码。 相反,必须安装并启动服务,然后将调试程序附加到服务进程。 有关详细信息,请参阅如何:调试 Windows 服务应用程序。
-
与某些项目类型不同,你必须为服务应用程序创建安装组件。 安装组件在服务器上安装并注册该服务,并使用 Windows 服务控制管理器 为服务创建条目。 有关详细信息,请参阅如何:将安装程序添加到服务应用程序。
-
服务应用程序的
Main
方法必须为项目包含的服务发出 Run 命令。Run
方法将服务加载到相应服务器上的服务控制管理器 中。 如果使用 Windows 服务 项目模板,则会自动为你编写此方法。 请注意,加载服务与启动服务不同。 有关详细信息,请参阅下面的“服务生存期”。 -
Windows 服务应用程序在不同于登录用户的交互式工作站的窗口站中运行。 窗口站是一个安全对象,它包含一个剪贴板、一个全局原子集和一组桌面对象。 由于 Windows 服务站不是交互式工作站,因此从 Windows 服务应用程序中引发的对话框将不会显示,并且可能导致程序停止响应。 同样,错误消息应记录在 Windows 事件日志中,而不是在用户界面中引发。
.NET Framework 支持的 Windows 服务类不支持与交互式工作站(即登录用户)的交互。 .NET Framework 也不包括表示工作站和桌面的类。 如果 Windows 服务必须与其他工作站进行交互,则需要访问非管理的 Windows API。 有关详细信息,请参阅 Windows SDK 文档。
Windows 服务与用户或其他工作站的交互必须经过精心设计,以便包括各种场景(如没有登录用户或用户具有一组意外的桌面对象)。 在某些情况下,编写在用户控制下运行的 Windows 应用程序可能更合适。
-
Windows 服务应用程序在其自己的安全上下文中运行,并在用户登录安装这些应用程序的 Windows 计算机之前启动。 应仔细规划要在哪个用户帐户中运行服务;在系统帐户下运行的服务具有比用户帐户更多的权限和特权。
服务生存期
一项服务在其生存期内会经历几个内部状态。 首先,服务会安装到它将在其上运行的系统上。 此过程执行服务项目的安装程序,并将该服务加载到该计算机的服务控制管理器 中。 服务控制管理器是 Windows 提供的用于管理服务的中央实用程序。
必须在服务加载完成后启动它。 启动该服务以允许它开始运行。 可以从服务“服务控制管理器” 、“服务器资源管理器” ,或从通过调用 Start 方法的代码来启动服务。 Start 方法将处理进程传递给应用程序的 OnStart 方法,并处理在那里定义的任何代码。
正在运行的服务可以在此状态下无限期地存在,直到它停止或暂停,或者直到计算机关闭。 服务可以三种基本状态之一存在:Running、Paused 或 Stopped。 该服务还可以报告挂起命令的状态:ContinuePending、PausePending、StartPending 或 StopPending。 这些状态指示命令已发出(例如,暂停正在运行的服务的命令),但尚未执行。 可以查询 Status 以确定服务所处的状态,或者在出现其中任一状态时使用 WaitForStatus 执行操作。
可以从“服务控制管理器” 、“服务器资源管理器” ,或通过调用代码中的方法来暂停、停止或恢复服务。 其中的每个操作都可以调用服务中的相关过程(OnStop、OnPause 或 OnContinue),可以在其中定义在服务更改状态时执行的其他处理进程。
服务类型
可以使用 .NET Framework 在 Visual Studio 中创建两种服务类型。 作为进程中唯一服务的服务将分配类型 Win32OwnProcess。 与其他服务共享进程的服务将分配类型 Win32ShareProcess。 可以通过查询 ServiceType 属性来检索服务类型。
如果查询未在 Visual Studio 中创建的现有服务,则可能偶尔会看到其他服务类型。 有关这些服务类型的更多信息,请参阅 ServiceType。
服务和 ServiceController 组件
ServiceController 组件用于连接到已安装的服务并操纵其状态;可以使用 ServiceController 组件启动和停止服务,暂停并继续其运行,并将自定义命令发送到服务。 但是,在创建服务应用程序时,无需使用 ServiceController 组件。 事实上,在大多数情况下,ServiceController 组件应存在于定义服务的 Windows 服务应用程序的单独应用程序中。
有关详细信息,请参阅 ServiceController。
要求
-
必须在 Windows 服务 应用程序项目或其他 .NET Framework(启用了在生成并从 ServiceBase 类继承时创建 .exe 文件的项目)中创建服务。
-
包含 Windows 服务的项目必须具有项目及其服务的安装组件。 这可以通过“属性” 窗口轻松完成。 有关详细信息,请参阅如何:将安装程序添加到服务应用程序。
请参阅
- Windows 服务应用程序
- 服务应用程序编程体系结构
- 如何:创建 Windows 服务
- 如何:安装和卸载服务
- 如何:启动服务
- 如何:调试 Windows 服务应用程序
- 演练:在组件设计器中创建 Windows 服务应用程序
- 如何:将安装程序添加到服务应用程序
从注册表删除服务项。
C:>sc delete
描述:
从注册表删除服务项。
如果服务正在运行,或另一进程已经打开
到此服务的句柄,服务将简单地标记为
删除。
用法:
sc <server> delete [service name]
Golang 实现Windows服务_Ango_的专栏-CSDN博客_golang windows 服务 https://blog.csdn.net/ango_/article/details/104161896
什么是windows服务
Windows 服务是主要用于服务器环境而长期运行的应用程序, 这类程序不需要有用户界面或者任何模拟输出。 任何的用户消息通常都是记录在Windows 事件日志里。Windows Service可以在操作系统启动的时候开始,一直在后台运行,当有需要时也可以手动启动,我们可以通过管理工具里面的服务进行统一管理。
当系统启动完毕后,Windows服务并不需要通过登陆页面后才能启动,即使用户注销登录也不会停止,通常不和用户产生交互。
而我们启动一般的exe文件却要先登陆Windows后才能启动它,通常还有一个用户界面,命令行或者是GUI界面,通常由用户手动启动和停止。
如何注册windows服务
手工注册Windows服务得用得到windows下cmd命令(管理员身份)
注册服务 [ServiceTest]:
sc create ServiceTest binpath="/path/to/exe"
1
启动服务:
sc start ServiceTest
1
停止服务、删除服务:
sc stop ServiceTest
sc delete ServiceTest
1
2
用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)
}
}
服务启动不了(ERROR:1053)的解决方法_x3230835的博客-CSDN博客 https://blog.csdn.net/x3230835/article/details/46313203
Error 1053:The service did not respond to the start or control request in a timely fashion”(错误 1053:服务没有及时响应启动或控制请求)错误信息”
protected override void OnStart( string[] args )
{
while(true){;}
}
一般是OnStart中有死循环,服务管理器没有检测到启动完成,超过一段时间后就会报错
解决方法:
把处理函数放在线程中
protected override void OnStart( string[] args )
{
th = new Thread( new ParameterizedThreadStart( Start ) );
th.Start( null );
}
private void Start( object obj )
{
while(true){;}
}
别忘了为OnStop回收th