Windows NT服务--独立的观点

简介:

在windows中,服务是一种特殊的进程,可以说它和用户无关,它的作用不是完成用户任务,而是进行一些管理类的操作或者通用的服务类操作,实际上windows服务就是一个可执行文件,但是远远不只是这些。

Windows NT的服务架构非常复杂,是整个系统架构中独立的一块。windows服务执行的往往都是一些无须用户介入的任务,也就是说它执行的任务不是具体的,而是具有支撑性质的,比较底层的,比如网络登录,文件驱动,设备驱动,ftp等等,其他的进程往往就和登录用户密切相关了,毕竟计算机就是让用户使用的,而其上执行的任务也就是用户要求的,因此用户是windows进程一个很重要的属性,同时也是操作系统本身一个很重要的性质,可以实现安全管理等相关操作。

windows服务主要由三部分组成,一是服务本身;二是服务控制管理器(SCM);三是服务控制程序(SCP)。SCM是个管理中心,管理着所有的线上服务,所谓线上服务就是已经安装的服务,SCP和SCM交互来管理服务本身,注意服务本身并不需要直接和SCM交互,这样就可以让写一个服务变得更加容易,人们可以像写普通的应用程序一样来完成一个服务的编程,唯一需要附加的就是和SCP接口就可以了,这样看来虽然windows服务的架构非常复杂,但是三者之间的耦合度却很低,足见设计的精妙。SCM维护着一个数据库,该数据库储存着已安装的服务和驱动程序的信息,SCM管理着它们,SCM根据这些信息控制服务的关闭和启动等行为,服务可以从SCM接收命令然后采取一定的动作,注意它是通过SCP来接收命令的,服务本身就是一个一直运行的应用程序,SCP作为一个 接口提供出来,用户可以通过它控制服务的行为,SCM同时也和SCP交互,在这繁复的数据流背后是成熟的RPC,windows中信号是不流行的,但是RPC却非常普遍,下面通过一个简单例子说明一下枝枝蔓蔓:

#include "stdafx.h"

#include.h>

void Install(char * name);

void Uninstall(char *name);

char *a = "mee11";

BOOL Running = TRUE;

SERVICE_STATUS_HANDLE hServiceStatus;

SERVICE_STATUS status;

SC_HANDLE hSCM;

int option(int argc, TCHAR* argv[])

{

hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);

if (argc <= 1) return 0;

if (_wcsicmp(argv[1], _T("-i")) == 0)

{

Install(a);

::CloseServiceHandle(hSCM);

return 1;

}

if (_wcsicmp(argv[1], _T("-u")) == 0)

{

Uninstall(a);

return 1;

}

return 0;

}

void Install(char *name ) //安装服务,实际上就是将该新服务的信息写入SCM管理的数据库中

{

if (!hSCM) return 0;

char szFilePath[260];

::GetModuleFileNameA(NULL, szFilePath, sizeof(szFilePath));

SC_HANDLE hService = ::CreateServiceA(hSCM,(LPCSTR)name,(LPCSTR)name,SERVICE_ALL_ACCESS,SERVICE_WIN32_OWN_PROCESS,SERVICE_DEMAND_START,SERVICE_ERROR_NORMAL,szFilePath,NULL,NULL,NULL,NULL,NULL);

if (!hService) {

::CloseServiceHandle(hSCM);

return ;

}

char szKey[256];

HKEY hKey = NULL;

strcpy(szKey, "SYSTEM//CurrentControlSet//Services//EventLog//Application//");

strcat(szKey, name);

if (::RegCreateKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey) != ERROR_SUCCESS) {

::CloseServiceHandle(hService);

::CloseServiceHandle(hSCM);

return;

}

::RegSetValueEx(hKey,_T("EventMessageFile"),0,REG_EXPAND_SZ, (CONST BYTE*)szFilePath,strlen(szFilePath) + 1);

DWORD dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;

::RegSetValueEx(hKey,_T("TypesSupported"),0,REG_DWORD,(CONST BYTE*)&dwData,sizeof(DWORD));::RegCloseKey(hKey);

::CloseServiceHandle(hService);

}

void Uninstall(char *name)

{

SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);

if (!hSCM) return ;

SC_HANDLE hService = ::OpenServiceA(hSCM,name,DELETE);

if (hService) {

if (::DeleteService(hService))

::CloseServiceHandle(hService);

}

::CloseServiceHandle(hSCM);

}

static void WINAPI Handler(DWORD dwOpcode)

{ //注意是在这个Handler回调中处理的SCM发来的命令,这里要做的就是设置控制变量,间接改变服务的运行行为。

switch (dwOpcode) {

case SERVICE_CONTROL_STOP:

status.dwCurrentState = SERVICE_STOP_PENDING;

::SetServiceStatus(hServiceStatus, &status);

Running = FALSE;

break;

default:

break;

}

::SetServiceStatus(hServiceStatus, &status);

}

static void WINAPI ServiceMaina(DWORD dwArgc, LPTSTR* lpszArgv)

{

hServiceStatus = RegisterServiceCtrlHandlerA(a,Handler);

::SetServiceStatus(hServiceStatus, &status);

status.dwCurrentState = SERVICE_RUNNING;

::SetServiceStatus(hServiceStatus, &status);

while (Running)

{

//做具体的服务吧,就像这是一个普通的应用程序一样

}

status.dwCurrentState = SERVICE_STOP_PENDING;

::SetServiceStatus(hServiceStatus, &status);//最后告诉SCM,这个服务停止了。

}

void StartService()

{

SERVICE_TABLE_ENTRY st[] = {

{(LPWSTR)a, ServiceMain},{NULL, NULL}};

status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;

status.dwCurrentState = SERVICE_STOPPED;

status.dwControlsAccepted = SERVICE_ACCEPT_STOP;

status.dwWin32ExitCode = 0;

status.dwServiceSpecificExitCode = 0;

status.dwCheckPoint = 0;

status.dwWaitHint = 0;

::StartServiceCtrlDispatcher(st);//分派器开始,服务即将开始运行

}

int _tmain(int argc, _TCHAR* argv[])

{

if(!option(argc, argv))

{

StartService();

}

return 0;

}

看到在RegisterServiceCtrlHandlerA中注册的Handler了吧,Handler就相当于一个控制器,这个Handler就是负责接收和处理命令的,它和主服务在不同的线程当中,主服务也就是上面例子中的while循环线程可以旁若无人的做任何事情,控制变量是全局的,可以在别的线程被改变,这个变量控制着服务的关闭行为,一切就是这么简单。关于服务的调试,可以用远程调试的办法进行。

windows专门为服务这个东西设计了如此复杂的机制,看得出服务的重要性,不过也不一定,windows本身就是微核结构而且内部大量使用了C/S架构,它为任何东西单独设计一个机制都不足为奇。它的API相当复杂,之所以这样就使因为windows是面向用户的,而用户是很难缠的,因此其api就提供了很多策略性的东西,当然也就相对复杂,windows服务仅仅是其中的一块而已,不过即使这样,windows的设计者还是做的很不错,程序员几乎不用费力就可以完成一个服务框架,当然如果深入一些,还有更加复杂的,不过那就涉及到一个新机制了,这就是svchost,很熟悉吧,不过不说了,我不喜欢讨论网上一搜一堆的东西,我比较喜欢思想性的东西,最起码还可能遭到一些反驳...


 本文转自 dog250 51CTO博客,原文链接:http://blog.51cto.com/dog250/1273461

相关文章
|
1月前
|
Linux Shell Windows
通过Linux挂载Windows端NFS服务实现板端Linux传输文件到PC
通过Linux挂载Windows端NFS服务实现板端Linux传输文件到PC
|
1月前
|
存储 安全 数据安全/隐私保护
Windows部署WebDAV服务并映射到本地盘符实现公网访问本地存储文件
Windows部署WebDAV服务并映射到本地盘符实现公网访问本地存储文件
263 0
|
2月前
|
Java Unix 应用服务中间件
使用java service wrapper把windows flume做成服务
使用java service wrapper把windows flume做成服务
|
2月前
|
Windows
修改Windows服务的配置
修改Windows服务的配置
|
3月前
|
Arthas 监控 Java
Arthas 可以用于监控和诊断在 Windows 系统下部署的 Tomcat 服务
Arthas 可以用于监控和诊断在 Windows 系统下部署的 Tomcat 服务
175 2
|
26天前
|
Shell Windows
Windows服务器 开机自启动服务
Windows服务器 开机自启动服务
14 0
|
16天前
|
Kubernetes Linux Windows
kubectl 本地远程链接k8s多个集群,远程管控多集群,查看日志 部署服务(windows版)
kubectl 本地远程链接k8s多个集群,远程管控多集群,查看日志 部署服务(windows版)
226 0
|
4月前
|
网络协议 安全 文件存储
Windows本地搭建WebDAV服务并使用内网穿透远程访问【无公网IP】
Windows本地搭建WebDAV服务并使用内网穿透远程访问【无公网IP】
|
4月前
|
监控 Linux 定位技术
Linux【环境部署 01】NTP时间服务器搭建及Linux+Windows客户端使用(一篇学会使用NTP服务)
Linux【环境部署 01】NTP时间服务器搭建及Linux+Windows客户端使用(一篇学会使用NTP服务)
658 0
|
3天前
|
网络协议 安全 测试技术
Windows安装禅道系统结合Cpolar实现公网访问内网BUG管理服务
Windows安装禅道系统结合Cpolar实现公网访问内网BUG管理服务