在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