
什么是服務(wù)
維基百科: Architecture of Windows NT 、Windows service
The term "service" in this context generally refers to a callable routine, or set of callable routines. This is distinct from the concept of a "service process", which is a user mode component somewhat analogous to a daemon in Unix-like operating systems.
從 Microsoft 技術(shù)文檔 找的一些描述:
A service is an application type that runs in the system background and is similar to a UNIX daemon application. Services provide core operating system features, such as Web serving, event logging, file serving, help and support, printing, cryptography, and error reporting. With the Services snap-in, you can manage services on local or remote computers.
A service is a long-running executable that does not support a user interface, and which might not run under the logged-on user account. The service can run without any user being logged on to the computer.
Microsoft Windows services, formerly known as NT services, enable you to create long-running executable applications that run in their own Windows sessions. These services can be automatically started when the computer boots, can be paused and restarted, and do not show any user interface. These features make services ideal for use on a server or whenever you need long-running functionality that does not interfere with other users who are working on the same computer. You can also run services in the security context of a specific user account that is different from the logged-on user or the default computer account.
You can easily create services by creating an application that is installed as a service. For example, suppose you want to monitor performance counter data and react to threshold values. You could write a Windows Service application that listens to the performance counter data, deploy the application, and begin collecting and analyzing data.
A service application conforms to the interface rules of the Service Control Manager (SCM). It can be started automatically at system boot, by a user through the Services control panel applet, or by an application that uses the service functions. Services can execute even when no user is logged on to the system.
A driver service conforms to the device driver protocols. It is similar to a service application, but it does not interact with the SCM. For simplicity, the term service refers to a service application in this overview.
按我的理解,服務(wù)就是一個抽象概念,是一套被設(shè)計用于管理那些 需要長時間運行、具有依賴關(guān)系、沒有用戶界面、不需要用戶登錄、需要特殊權(quán)限、可跟隨系統(tǒng)啟動而自動運行的程序 的體系結(jié)構(gòu),而相關(guān)的數(shù)據(jù)庫、程序、進程都是其中不可或缺的一部分。用戶向系統(tǒng)注冊服務(wù)后便由系統(tǒng)來自動調(diào)度服務(wù)而無需用戶參與。任務(wù)管理器的服務(wù)標(biāo)簽頁中,每行數(shù)據(jù)可以表示一個服務(wù),實際數(shù)據(jù)存儲于注冊表中:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services
服務(wù)這個術(shù)語更傾向于描述程序的運行方式,比如以服務(wù)的方式運行( run as a service )。
Windows 中的服務(wù)和 Linux 中的服務(wù)從目的性上( 后臺運行、開機啟動等 )來說比較類似,只不過實現(xiàn)方式和運行機制有所不同。 Linux 服務(wù)通常會在 /etc/init.d 目錄下有一個對應(yīng)的配置腳本( 參考 ),比起在 Windows 上更直觀易懂,配置服務(wù)也更容易。
服務(wù)變更歷史
- What's New in Services for Windows 8
- What's New in Services for Windows 7
- Service Changes for Windows Vista
服務(wù)與程序和進程的關(guān)系
類似的問答
- What's the difference between an Application, a Process, and a Service?
- What is the difference between 'Application' and 'Process' in OS X?
- windows 下的服務(wù)和進程有什么區(qū)別?
相關(guān)術(shù)語解釋
操作系統(tǒng)
Operating System
操作系統(tǒng)是管理計算機資源并為用戶提供服務(wù)的系統(tǒng)軟件,作為硬件與應(yīng)用軟件之間的接口,操作系統(tǒng)起著承上啟下的作用。
計算機系統(tǒng)大體上可以分為三個部分:硬件、系統(tǒng)軟件和應(yīng)用軟件。硬件是所有軟件運行的物質(zhì)基礎(chǔ)。而操作系統(tǒng)(簡稱 OS)則是最重要的系統(tǒng)軟件。是管理計算機系統(tǒng)資源、控制程序執(zhí)行的系統(tǒng)軟件。操作系統(tǒng)作為計算機用戶與計算機硬件之間的接口程序,向用戶和應(yīng)用軟件提供各種服務(wù),合理組織計算機工作流程,并為用戶使用計算機提供良好運行環(huán)境。
操作系統(tǒng)的核心任務(wù)是管理計算機系統(tǒng)中的資源。操作系統(tǒng)為用戶提供簡單、有效的資源使用方法,分配資源使用權(quán),解決資源爭用沖突,跟蹤資源使用狀況,最大限度地實現(xiàn)資源共享,提高資源利用率。而操作系統(tǒng)地其他任務(wù),如擴充機器功能、屏蔽使用細(xì)節(jié)、方便用戶使用、合理組織工作流程、管理人機界面等,都是圍繞著資源管理任務(wù)實現(xiàn)的。
資源
所謂資源,泛指在計算機系統(tǒng)中,用戶能夠使用的各種硬件和軟件部分。計算機系統(tǒng)中可以使用的硬件資源主要是處理機、存儲器、輸入/輸出設(shè)備等。而軟件資源則包括相應(yīng)的程序和數(shù)據(jù)等。
程序
Computer Program
在早期的計算機中,人們是直接用機器語言(即機器指令代碼)來編寫程序的,這種方式編寫的程序稱為 手編程序 。這種用機器語言書寫的程序,計算機完全可以“識別”并能執(zhí)行,所以又叫做 目的程序 。
用某種高級語言或匯編語言編寫的程序稱為源程序 ,源程序不能直接在計算機上執(zhí)行。如果源程序是用匯編語言編寫的,則需要一個匯編程序?qū)⑵浞g成目標(biāo)程序后才能執(zhí)行。如果源程序是用某種高級語言編寫的,則需要對應(yīng)的解釋程序或者編譯程序?qū)ζ溥M行翻譯,然后在機器上運行。
通常用源代碼( Source code ,人類可讀的符合程序設(shè)計語言規(guī)范書寫的文本文件 )表示源程序,而程序泛指目的程序,即可執(zhí)行的文件( Executable ),不需要關(guān)聯(lián) 打開方式 就能雙擊打開的文件。在 Windows 中除了常見的 exe 文件和批處理文件外,還可以用注冊表查詢 HKEY_CLASSES_ROOT 中數(shù)據(jù)為 "%1" %* 的項。
- What are the differences between a Program, an Executable, and a Process?
- 操作系統(tǒng)是如何運行可執(zhí)行文件的?
- 什么是程序(Program)
軟件
Software
軟件是一系列文檔、程序以及其正常運行所需的相關(guān)數(shù)據(jù)的集合。我們常說的軟件( 手機上的 APP )一般指的是運行在操作系統(tǒng)之上的應(yīng)用軟件( Application ),比如 QQ ,打開安裝目錄可以看到除了 exe 文件外還有一堆其他的文件。
應(yīng)用軟件是指計算機用戶利用計算機的軟件、硬件資源為某一專門的應(yīng)用目的而開發(fā)的軟件。例如,科學(xué)計算、工程設(shè)計、數(shù)據(jù)處理、事務(wù)處理和過程控制等方面的程序,以及文字處理軟件、表格處理軟件、輔助設(shè)計軟件(CAD)和實時處理軟件等。
應(yīng)用與任務(wù)
App & Task
對應(yīng) win10 任務(wù)管理器中進程標(biāo)簽頁下的應(yīng)用分類,每個應(yīng)用展開后會有任務(wù)。應(yīng)用是存在前臺窗口與用戶進行交互的主進程,任務(wù)是其子進程或者抽象出來的窗口。像常用的 合并任務(wù)欄按鈕 設(shè)置項,沒合并前顯示全部的窗口任務(wù),合并后只顯示應(yīng)用。( 打開任務(wù)欄設(shè)置 )
它們和進程之間的對應(yīng)關(guān)系不太好描述,自行感受吧:
- 打開兩個文件夾窗口后,可以看到 1 個資源管理器應(yīng)用、 2 個文件夾任務(wù)、 1 個 explorer.exe 進程。
- 使用
regedit -m命令打開兩個注冊表編輯器,可以看到 2 個應(yīng)用、 每個應(yīng)用 1 個任務(wù)、 2 個 regedit.exe 進程。 - 打開 nginx 后不顯示應(yīng)用和任務(wù),但可以看到 2 個 nginx.exe 后臺進程。
- 像 VMware 虛擬機,最小化在托盤時不顯示應(yīng)用和任務(wù),而雙擊打開后可以看到 1 個應(yīng)用、 2 個任務(wù)、 3 個進程。
進程
Process
進程是程序的一次執(zhí)行,該程序可以和其他程序并發(fā)執(zhí)行。進程通常是由程序、數(shù)據(jù)和進程控制塊(PCB)組成的。
在操作系統(tǒng)中,通常使用 進程(process) 這一概念描述程序的動態(tài)執(zhí)行過程。通俗地講,程序是靜態(tài)實體,而進程是動態(tài)實體,是執(zhí)行中的程序。進程不僅僅包含程序代碼,也包含了當(dāng)前的狀態(tài)(這由程序計數(shù)器和處理機中的相關(guān)寄存器表示)和資源。因此,如果兩個用戶用同樣一段代碼分別執(zhí)行相同功能的程序,那么其中的每一個都是一個獨立的進程。雖然其代碼是相同的,但是數(shù)據(jù)卻未必相同。
進程是可并發(fā)執(zhí)行的程序在一個數(shù)據(jù)集合上的運行過程,是系統(tǒng)進行資源分配和調(diào)度的基本單位,是線程的容器。迄今為止對這一概念還沒有一個確切的統(tǒng)一的描述。一個進程是特定程序的一個實例( instance ),在運行過程中可以創(chuàng)建自己的子進程。 后臺進程 就是不與用戶進行交互( 隱藏起來 )的進程。
程序和進程就是 名詞 與 現(xiàn)在進行時 的關(guān)系,常見的比喻是菜譜和做菜過程。
服務(wù)程序
一種符合 服務(wù)控制管理器 (SCM) 接口規(guī)范的應(yīng)用程序,即 Service Program ,是服務(wù)啟動實際所執(zhí)行的可執(zhí)行文件。( 詳見下文 )
以上引用內(nèi)容摘自 計算機組成原理第 4 版 和 軟件設(shè)計師教程(第三版)(修訂版) ,多年以后再回顧教材發(fā)現(xiàn)上課學(xué)的東西早忘得一干二凈了,還好書留著可以當(dāng)詞典用。
它們之間的關(guān)系:
- 用戶雙擊 > 運行 程序 > 產(chǎn)生 進程 。
- 啟動服務(wù) > 運行 服務(wù)程序 > 產(chǎn)生 服務(wù)進程 。
這些術(shù)語本就比較抽象,再加上翻譯、口語化、場景( 開發(fā)還是使用 )等等因素就容易造成歧義令人困惑。就像 1+1=2 一樣,不需要糾結(jié)為什么是這樣,只需要知道這是約定成俗的,了解多了自然就懂了。這些術(shù)語的存在是為了幫助人們更容易理解復(fù)雜抽象的計算機軟件體系結(jié)構(gòu)。口語中的服務(wù)通常在各個語境中分別指代服務(wù)本身、服務(wù)程序和服務(wù)進程,能明白其中的含義就行了。
什么是服務(wù)控制管理器 (SCM)
Service Control Manager (SCM) is a special system process under the Windows NT family of operating systems, which starts, stops and interacts with Windows service processes. It is located in the
%SystemRoot%\System32\services.exeexecutable. Service processes interact with SCM through a well-defined API, and the same API is used internally by the interactive Windows service management tools such as the MMC snap-inServices.mscand the command-line Service Control utilitysc.exe. Terminating this file is used as a method of causing the Blue Screen of Death.
我們都知道服務(wù)設(shè)置為自動后就能開機啟動,而這個操控者就是 SCM 。SCM 是一個特殊的系統(tǒng)進程,它執(zhí)行各種與服務(wù)有關(guān)的任務(wù)。它跟隨系統(tǒng)啟動而運行,之后它便會啟動所有設(shè)置了 自動啟動 的服務(wù)以及它們所依賴的 手動啟動 的服務(wù)。SCM 維護了一個數(shù)據(jù)庫來存儲已安裝的服務(wù),并提供了安全統(tǒng)一的方式來管理它們。
SCM 就是整個服務(wù)體系的核心,由它直接管理服務(wù)的一切配置和行為,它提供一系列 函數(shù) 供其他程序調(diào)用以間接控制服務(wù):
- 維護已安裝服務(wù)的數(shù)據(jù)庫。
- 在系統(tǒng)啟動時或按需啟動服務(wù)和驅(qū)動程序服務(wù)。
- 枚舉已安裝的服務(wù)和驅(qū)動程序服務(wù)。
- 維護運行服務(wù)和驅(qū)動服務(wù)的狀態(tài)信息。
- 將控制請求傳輸?shù)秸谶\行的服務(wù)。
- 鎖定和解鎖服務(wù)數(shù)據(jù)庫。
調(diào)用這些函數(shù)的程序根據(jù)職能主要分為以下幾類:
服務(wù)程序
Service Program
為一個或多個服務(wù)提供可執(zhí)行代碼的應(yīng)用程序。主要用到了連接 SCM 和修改服務(wù)狀態(tài)的函數(shù)。一些 服務(wù)程序 還會通過命令行參數(shù)實現(xiàn)自 安裝 的功能,比如 mysqld --install 。
通常 服務(wù)程序 作為控制臺程序直接運行而不是通過服務(wù)運行時會報錯:
# 參考 StartServiceCtrlDispatcher 的返回值
1063 (ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
服務(wù)配置程序
Service Configuration Program
主要用于增刪改查 SCM 數(shù)據(jù)庫中服務(wù)配置信息的程序。雖然可以通過注冊表管理數(shù)據(jù)庫,但還是應(yīng)該只使用 SCM 提供的相關(guān)函數(shù)以確保配置的正確性。系統(tǒng)自帶的命令行工具 Sc.exe 就包含此類功能。
服務(wù)控制程序
Service Control Program
主要用于 啟動服務(wù)程序 和 控制服務(wù)進程 的程序,后面簡稱 SCP 。它們只是向 SCM 發(fā)送請求,再由 SCM 轉(zhuǎn)發(fā)給服務(wù)。系統(tǒng)自帶的命令行工具 Sc.exe 、net.exe 就包含此類功能。
SCM 以串行的方式依次處理請求,一個服務(wù)處理完一個請求后 SCM 才會發(fā)送下一個請求。因此如果服務(wù)正忙于處理請求時 ,之后的 StartService 和 ControlService 都會阻塞,超時( 30 秒 )直接返回錯誤。
SCM 同時是一個 RPC 服務(wù)器,因此服務(wù)配置和服務(wù)控制程序可以管理遠(yuǎn)程主機上的服務(wù)。
進一步了解服務(wù)
服務(wù)屬性
所有屬性值詳見下面的鏈接:
- Win32_Service class
- CreateService Parameters
- sc.exe create
- Database of Installed Services
- Service Record List
- ServiceInstaller Properties
提一下 ServiceName 、 DisplayName 、 Description 這三個屬性, ServiceName 才是每個服務(wù)的唯一標(biāo)識,比較時不區(qū)分大小寫,另外兩個則是顯示名稱和描述,是為了幫助用戶識別這個服務(wù)的作用。另外, DisplayName 還用于 NET START 命令。然而在 任務(wù)管理器 和 服務(wù) 以及其他第三方工具的界面中通常只顯示兩個字段( 名稱和描述 ),內(nèi)容則是這三個屬性混用或者組合而成的,很混亂。
服務(wù)類型
| 名稱 | 數(shù)值 | 說明 |
|---|---|---|
| SERVICE_ADAPTER | 0x00000004 | 保留的。 |
| SERVICE_FILE_SYSTEM_DRIVER | 0x00000002 | 文件系統(tǒng)驅(qū)動程序服務(wù)。 |
| SERVICE_KERNEL_DRIVER | 0x00000001 | 設(shè)備驅(qū)動程序服務(wù)。 |
| SERVICE_RECOGNIZER_DRIVER | 0x00000008 | 保留的。 |
| SERVICE_WIN32_OWN_PROCESS | 0x00000010 | 獨占一個進程的服務(wù)。 |
| SERVICE_WIN32_SHARE_PROCESS | 0x00000020 | 與其他服務(wù)共享一個進程的服務(wù)。 |
| SERVICE_USER_OWN_PROCESS | 0x00000050 | 在登錄的用戶帳戶下運行的獨占服務(wù)。 |
| SERVICE_USER_SHARE_PROCESS | 0x00000060 | 在登錄的用戶帳戶下運行的共享服務(wù)。 |
| SERVICE_INTERACTIVE_PROCESS | 0x00000100 | 可交互的服務(wù) 。Windows Vista 起服務(wù)不能直接與用戶交互。 |
服務(wù)可以通過調(diào)用 SetServiceBits 函數(shù)來注冊其他類型信息。調(diào)用 NetServerGetInfo 和 NetServerEnum 函數(shù)獲取支持的服務(wù)類型。( 來源 )
SERVICE_INTERACTIVE_PROCESS 需要和 SERVICE_WIN32_OWN_PROCESS 或 SERVICE_WIN32_SHARE_PROCESS 組合使用,并且要在 LocalSystem 帳戶上下文中運行。
- 驅(qū)動程序服務(wù) 的運行和管理方式有所不同,本文先不做深入了解了。
-
用戶服務(wù) 在用戶登錄時使用模板創(chuàng)建,退出時刪除,起到用戶級別的隔離。名稱形如
OneSyncSvc_ff97b,這個后綴是每次登錄后隨機生成的。 - 保護反惡意軟件服務(wù)
服務(wù)啟動類型
| 名稱 | 數(shù)值 | 說明 |
|---|---|---|
| SERVICE_AUTO_START | 0x00000002 | 系統(tǒng)啟動時由 SCM 自動啟動的服務(wù)。詳見 自動啟動服務(wù) 。DelayedAutostart 設(shè)為 1 時表示 自動(延遲啟動) 。 |
| SERVICE_BOOT_START | 0x00000000 | 由系統(tǒng)加載程序啟動的設(shè)備驅(qū)動程序。此值僅對驅(qū)動程序服務(wù)有效。 |
| SERVICE_DEMAND_START | 0x00000003 | 手動,當(dāng)進程調(diào)用 StartService 函數(shù)時由 SCM 啟動的服務(wù) 。詳見 按需啟動服務(wù) 。 |
| SERVICE_DISABLED | 0x00000004 | 禁止啟動的服務(wù)。嘗試啟動此類服務(wù)會返回 錯誤代碼 ERROR_SERVICE_DISABLED 。 |
| SERVICE_SYSTEM_START | 0x00000001 | 由 IoInitSystem 函數(shù)啟動的設(shè)備驅(qū)動程序。此值僅對驅(qū)動程序服務(wù)有效。 |
服務(wù)狀態(tài)
| 名稱 | 數(shù)值 | 說明 |
|---|---|---|
| SERVICE_CONTINUE_PENDING | 0x00000005 | 服務(wù)正在恢復(fù)。 |
| SERVICE_PAUSE_PENDING | 0x00000006 | 服務(wù)正在暫停。 |
| SERVICE_PAUSED | 0x00000007 | 服務(wù)已暫停。 |
| SERVICE_RUNNING | 0x00000004 | 服務(wù)正在運行。 |
| SERVICE_START_PENDING | 0x00000002 | 服務(wù)正在啟動。 |
| SERVICE_STOP_PENDING | 0x00000003 | 服務(wù)正在停止。 |
| SERVICE_STOPPED | 0x00000001 | 服務(wù)未運行。 |
服務(wù)運行后需要及時正確地向 SCM 更新自己最新的 狀態(tài) ,這樣 SCP 才能通過 SCM 查詢服務(wù)的狀態(tài)。服務(wù)的狀態(tài)決定了服務(wù)和 SCM 之間該如何交互。例如,如果服務(wù)正處于 SERVICE_STOP_PENDING 狀態(tài),則 SCM 不會向服務(wù)發(fā)送進一步的控制請求,因為此狀態(tài)指示服務(wù)正在關(guān)閉。
The following table shows the action of the SCM in each of the possible service states.
服務(wù)的初始化狀態(tài)是 SERVICE_STOPPED ,主要的合法轉(zhuǎn)換過程見下圖:

服務(wù)程序啟動過程
看不到 StartService 的底層實現(xiàn),我猜測 SCM 啟動服務(wù) 的大概流程應(yīng)該是這樣的( 參考 ):
SCP 調(diào)用 StartService 。
-
SCM 準(zhǔn)備啟動服務(wù)。
如果多個服務(wù)共享一個進程且該進程已存在則獲取進程對應(yīng)的連接。
-
否則創(chuàng)建新的服務(wù)進程( 將登錄令牌分配給進程 ),等待建立連接。
在 入口點 中調(diào)用 StartServiceCtrlDispatcher :
- 建立主線程和 SCM 之間的連接( 命名管道 )。
- 將主線程作為 dispatcher 線程 駐留在一個循環(huán)內(nèi)接收來自 SCM 的請求。
- 直到發(fā)生錯誤或者進程中所有服務(wù)都結(jié)束了才會使主線程繼續(xù)往下執(zhí)行。
默認(rèn)超過 30 秒沒有調(diào)用 StartServiceCtrlDispatcher 會直接終止進程。
事件查看器 > 自定義視圖 > 管理事件 > 服務(wù)啟動失敗修改超時時間 ( 重啟才會生效 ):
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control ServicesPipeTimeout = 60000 -
連接建立時, SCM 發(fā)送 啟動請求 并傳遞啟動參數(shù)。
當(dāng)收到通知用于執(zhí)行 ServiceMain 的線程創(chuàng)建成功后, StartService 就直接返回以繼續(xù)執(zhí)行 SCP 中的代碼( 可定期 查詢 或者 監(jiān)聽 服務(wù)的最新狀態(tài) )。
-
SCM 繼續(xù)等待進程退出( 表示啟動失敗 )或者報告 SERVICE_RUNNING 狀態(tài)。
如果服務(wù)在 80 秒內(nèi)沒有更新其狀態(tài),則 SCM 會認(rèn)為服務(wù)發(fā)生了錯誤,將記錄一個事件并停止服務(wù)( 不確定是否會終止進程 )。
當(dāng) SCM 得知服務(wù)正在運行后便會 釋放 服務(wù)鎖 。
dispatcher 線程 的請求處理流程:
-
啟動請求
新建線程調(diào)起此服務(wù)對應(yīng)的 ServiceMain 并通知 SCM 線程創(chuàng)建成功。
-
調(diào)用 RegisterServiceCtrlHandler 注冊 Service Control Handler 函數(shù)以監(jiān)聽來自 SCM 的 控制請求 。
由于調(diào)用 SetServiceStatus 依賴于 RegisterServiceCtrlHandler 返回的 服務(wù)狀態(tài)句柄 ,所以只有將 RegisterServiceCtrlHandler 放置在 ServiceMain 中最開始的位置才能夠在發(fā)生錯誤時總能將狀態(tài)更新為 SERVICE_STOPPED 。
-
執(zhí)行服務(wù)初始化邏輯并更新服務(wù)狀態(tài)為 SERVICE_RUNNING 。
初始化過程應(yīng)盡可能快( 不超過 1 秒 ),否則要考慮特殊方法去優(yōu)化。
-
執(zhí)行服務(wù)實際的業(yè)務(wù)邏輯。
避免直接調(diào)用 ExitThread 來結(jié)束線程,這樣做會跳過清理任務(wù)而導(dǎo)致內(nèi)存泄漏。
-
-
控制請求 ( ControlService )
在當(dāng)前線程上下文中調(diào)起 Handler ,根據(jù)請求的 控制代碼 執(zhí)行對應(yīng)的業(yè)務(wù)代碼。
Handler 被調(diào)用的時候,如果業(yè)務(wù)代碼會導(dǎo)致服務(wù)狀態(tài)發(fā)生變化則一定要記得調(diào)用 SetServiceStatus ,如果不會導(dǎo)致狀態(tài)變化則不需要調(diào)用。
控制代碼 除了已規(guī)定的幾種外還可以是用戶自定義的代碼( 128-255 )如果有 權(quán)限 的話。
以上流程只是我根據(jù)文檔整理出來的,跟著代碼走一遍也許能有進一步的理解??次臋n的時候注意結(jié)合 About Services 、Using Services 、winsvc ,因為一個概念的內(nèi)容可能會分散在三個部分中。
什么是 Svchost
前面提到了 與其他服務(wù)共享一個進程的服務(wù) ,可以在多個服務(wù)之間共享代碼,一個常見的例子就是服務(wù)主機 Svchost.exe ,它用來托管系統(tǒng)內(nèi)部的服務(wù)( DLL 形式 )。
Svchost.exe ( 服務(wù)主機 ,或 SvcHost )是一個系統(tǒng)進程,它可以承載 Windows NT 系列操作系統(tǒng)中的一個或多個 Windows 服務(wù) 。Svchost 在共享服務(wù)進程的實現(xiàn)中是必不可少的,其中多個服務(wù)可以共享一個進程以減少資源消耗。將多個服務(wù)組合到一個進程中可以節(jié)省計算資源,這一考慮是 NT 設(shè)計人員特別關(guān)心的,因為創(chuàng)建 Windows 進程比其他操作系統(tǒng)( 例如 Unix 系列 )需要更多時間和消耗更多內(nèi)存。但是,如果其中一項服務(wù)導(dǎo)致未處理的異常,則整個進程可能會崩潰。此外,最終用戶可能更難以識別組件服務(wù)。
svchost 進程是在 Windows 2000 中引入的,盡管從 Windows NT 3.1 開始就存在對共享服務(wù)進程的底層支持。
它正確的位置應(yīng)該位于系統(tǒng)盤根目錄的 \Windows\system32 目錄下( 64 位系統(tǒng)則亦在系統(tǒng)盤根目錄的 \Windows\SysWOW64 )。 如果在其他地方看到,那么很可能是病毒程序。
微軟的 文檔 中明確指出了 Svchost.exe 保留供操作系統(tǒng)使用,不應(yīng)由非 Windows 服務(wù)使用,開發(fā)者應(yīng)實現(xiàn)自己的服務(wù)托管程序 ,所以使用 Svchost.exe 偽裝自己的行為就是在 耍流氓 。
早期的 Windows 一般只有有數(shù)幾個 svchost 進程,之后才慢慢增多并劃分成不同的主機組,不同組的服務(wù)在不同實例中運行。服務(wù)組是根據(jù)安全需求劃分的。
Windows 10 1703 起有了新的改動:內(nèi)存大于 3.5 GB 的機器自動為每個共享服務(wù)( 有例外 )分配一個單獨進程。所以在任務(wù)管理器中看到密密麻麻一堆 svchost 進程是很正常的現(xiàn)象。單獨進程會造成內(nèi)存開銷增大( 大概 500 MB ),但好處是加強了安全性、穩(wěn)定性、可擴展性,降低了故障排除的開銷,以及更細(xì)致的資源管理和診斷數(shù)據(jù)。( 參考 )
Svchost 參考資料
-
創(chuàng)建 SvcHost.exe 調(diào)用的服務(wù)原理與實踐
Svchost 本身只是作為服務(wù)宿主,并不實現(xiàn)任何服務(wù)功能,需要 Svchost 啟動的服務(wù)以動態(tài)鏈接庫形式實現(xiàn),在安裝這些服務(wù)時,把服務(wù)的可執(zhí)行程序指向 Svchost ,啟動這些服務(wù)時由 Svchost 調(diào)用相應(yīng)服務(wù)的動態(tài)鏈接庫來啟動服務(wù)。
那么 Svchost 如何知道某一服務(wù)是由哪個動態(tài)鏈接庫負(fù)責(zé)呢?這不是由服務(wù)的可執(zhí)行程序路徑中的參數(shù)部分提供的,而是服務(wù)在注冊表中的參數(shù)設(shè)置的,注冊表中服務(wù)下邊有一個 Parameters 子鍵其中的 ServiceDll 表明該服務(wù)由哪個動態(tài)鏈接庫負(fù)責(zé)。并且所有這些服務(wù)動態(tài)鏈接庫都必須要導(dǎo)出一個 ServiceMain() 函數(shù),用來處理服務(wù)任務(wù)。
How to determine what services are running under a SVCHOST.EXE process
編寫在 Svchost 中運行的 DLL
- How to run a dll as a service?
- SVCHOST 啟動服務(wù)實戰(zhàn)
- Window 服務(wù)學(xué)習(xí)筆記
- SvcHostDemo
- DllSrv
注冊任何程序為服務(wù)
一個標(biāo)準(zhǔn)的 服務(wù)程序 必須包含以下幾點 SCM 接口規(guī)范:
并不是說 SCM 會檢測程序里是否暴露了這幾個函數(shù), 而是一個服務(wù)想要正常運行就需要進程和 SCM 之間建立連接并能夠響應(yīng) SCM 發(fā)出的請求( 正確更新狀態(tài) ) ,要實現(xiàn)這一目的就不得不利用上面的幾個函數(shù)。比如用 sc 命令可以成功創(chuàng)建一個記事本的服務(wù),啟動服務(wù)的時候記事本也能打開,但因為沒法調(diào)用 StartServiceCtrlDispatcher , 30 秒之后就會被 SCM 強制關(guān)閉并提示啟動失敗。
我們?nèi)粘J褂玫能浖谠O(shè)計的時候大多沒有考慮以服務(wù)的形式運行,自然就不滿足上面的接口規(guī)范。如果我們非要以服務(wù)的形式運行就需要在它們和 SCM 之間構(gòu)建一座橋梁, SCM 通過這個 第三者 來間接控制進程,就像 Svchost 那樣。
找了幾個工具可以實現(xiàn)將任何程序注冊為 合法的 Windows 服務(wù) 。工具可以放在任何位置,不必放在系統(tǒng)目錄下,腳本在程序目錄下執(zhí)行。
RunAsSrv
最后更新時間: 2006-08-03
缺失 MSVCP71.DLL 和 MSVCR71.DLL ,下載后放到 exe 同級目錄下或者安裝 微軟常用運行庫合集 可以解決。
可能會被殺軟報病毒,介意者慎用。
runassrv add /cmdline:"C:\Users\test\Desktop\nginx\nginx.exe" /name:nginx_runassrv
SrvStart
最后更新時間: 2000-06-30
很古老的工具,號稱支持 Windows NT 4 之后的所有 Windows 版本。配置項很多,文檔也不是很清楚,調(diào)通有點費勁。
set name=nginx_srvstart
set startup_dir=C:\Users\test\Desktop\nginx
set startup=%startup_dir%\nginx.exe
set shutdown="%startup%" -p "%startup_dir%" -s stop
:: 寫入配置文件
(
echo [%name%]
echo startup_dir=%startup_dir%
echo startup=%startup%
echo shutdown=%shutdown%
) > nginx.ini
:: 創(chuàng)建服務(wù)
srvstart install %name% -c "%cd%\nginx.ini"
RunAsService
最后更新時間: 2020-10-01
需要安裝 .NET Framework 3.5 。官網(wǎng) 下載的不是最新的代碼,僅支持 exe 和 com 類型的文件作為啟動命令。
需要在管理員命令提示符中運行,否則會看不到任何信息。
RunAsService install "nginx_RunAsService" "C:\Users\test\Desktop\nginx\nginx.exe" -p "C:\Users\test\Desktop\nginx"
如果應(yīng)用子進程異常關(guān)閉了會導(dǎo)致無法直接關(guān)閉服務(wù),需要手動殺死 RunAsService.exe 進程。
srvany
srvany.exe 是 Microsoft Windows Resource Kits 工具集的一個實用的小工具,用于將任何 EXE 程序作為 Windows 服務(wù)運行。
官網(wǎng)已經(jīng)找不到了,只能通過第三方下載( 參考 )。支持 暫停/恢復(fù) 。
由于它只是一個服務(wù)外殼并沒有提供安裝命令,需要自己手動創(chuàng)建服務(wù):
set name=nginx_srvany
set startup_dir=C:\Users\test\Desktop\nginx
set startup=%startup_dir%\nginx.exe
set "AppParameters= "
set reg_path=HKLM\SYSTEM\CurrentControlSet\services\%name%\Parameters
:: 安裝服務(wù)
sc create %name% binPath= "%cd%\srvany.exe"
:: 配置注冊表中的服務(wù)參數(shù)
reg add "%reg_path%" /f /v AppDirectory /t REG_SZ /d "%startup_dir%"
reg add "%reg_path%" /f /v Application /t REG_SZ /d "%startup%"
reg add "%reg_path%" /f /v AppParameters /t REG_SZ /d "%AppParameters%"
有人專門為它寫了一個管理工具 SrvanyUI ( 已內(nèi)置 srvany ),還包括了對系統(tǒng)服務(wù)的管理,可以擺脫注冊表操作。

NSSM
最后更新時間: 2017-05-16
nssm is a service helper which doesn't suck. srvany and other service helper programs suck because they don't handle failure of the application running as a service.
提供了其他工具沒有的異常處理機制,注冊表的結(jié)構(gòu)類似于 srvany 。也可通過 Chocolatey 的方式安裝, Chocolatey 中的 nginx 就是通過這種方式創(chuàng)建服務(wù)的。
nssm install nginx_nssm "C:\Users\test\Desktop\nginx\nginx.exe"
也可以使用命令打開服務(wù)的配置界面:
nssm install nginx_nssm

winsw
Windows Service Wrapper
根據(jù)配置文件來加載安裝和啟動配置 ,類似于 SrvStart 的升級版。 V2 版本創(chuàng)建一個服務(wù)就要復(fù)制一份程序的做法略顯笨重,在 V3 版本中增加了全局方式。
V2 版本的配置過程:
set "name=nginx_winsw"
set startup_dir=C:\Users\test\Desktop\nginx
set startup=%startup_dir%\nginx.exe
copy /y WinSW-x64.exe %name%.exe
:: 寫入配置文件
(
echo id: %name%
echo name: ''
echo description: ''
echo executable: '"%startup%"'
echo arguments: -p "%startup_dir%"
echo stopArguments: -p "%startup_dir%" -s stop
) > %name%.yml
:: 安裝服務(wù)
%name%.exe install
整體使用下來 NSSM 體驗最好,功能多使用也方便。 winsw 也不錯,畢竟有配置文件更適合復(fù)雜配置以及批量安裝和遷移。而 SrvanyUI 是 UI 最強大的,上手難度最低適合普通用戶。
此類工具畢竟需要高權(quán)限,出于安全方面考慮還是建議使用開源項目。
nginx 服務(wù)
nginx 說實話不太適合做成服務(wù)的形式,管理起來也比較麻煩,而且上面的工具中除了 NSSM 和 SrvStart 外都不能正常關(guān)閉服務(wù),不是進程沒殺全就是其他的異常。我更喜歡的做法:
把快捷方式丟到開始菜單的啟動項(
shell:startup)中用于開機啟動。-
再建兩個快捷方式改參數(shù)丟到任務(wù)欄工具欄中用于關(guān)閉和重啟:
:: 關(guān)閉 nginx -s stop :: 重啟 nginx -s reload
C# 編寫服務(wù)程序
這里演示如何在 Visual Studio 中創(chuàng)建可向事件日志中寫入消息的 Windows 服務(wù)應(yīng)用程序。( 如何調(diào)試 )
具體步驟可以看 微軟文檔 ,只是機翻的文檔很別扭,我重新整理了一下。
在 .NET 5.0 SDK 或更高版本 中可以使用 BackgroundService 創(chuàng)建 Windows 服務(wù)。( demo )
下載安裝 Visual Studio
新版安裝程序還是很清爽的,按需選擇,不像以前那樣一股腦安裝各種不需要的東西,太占空間了。
只是為了測試,勾選 .NET 桌面開發(fā) 即可,安裝占用空間( 不壓縮 C 盤 )大概 7.36 G 。

新建項目
以 管理員權(quán)限 運行 VS 并新建項目 WindowsServiceTest 。
語言選擇 C# ,平臺選擇 Windows ,選中 Windows 服務(wù) 模板。( 可直接搜索 )
.NET Framework 4.7.2

修改代碼
在 解決方案資源管理器 中,選擇默認(rèn)創(chuàng)建的 Service1.cs 右鍵重命名( F2 )為 MyNewService.cs 并 切換到代碼視圖 。
-
Program.cs
using System.ServiceProcess; namespace WindowsServiceTest { internal static class Program { /// <summary> /// 應(yīng)用程序的主入口點。 /// </summary> static void Main(string[] args) { ServiceBase[] ServicesToRun = new ServiceBase[] { new MyNewService(args) }; ServiceBase.Run(ServicesToRun); } } } -
MyNewService.cs
設(shè)置屬性 CanPauseAndContinue 是為了啟用 暫停/恢復(fù) 功能,可以在 屬性 窗口直接設(shè)置,這里直接寫死在初始化代碼里。
修改 ServiceName 屬性值為 MyNewService ( 可選 )
注意有兩個參數(shù):一個是構(gòu)造方法中的初始化參數(shù),另一個是 OnStart 方法中的啟動參數(shù)。
using System; using System.Diagnostics; using System.ServiceProcess; using System.Timers; namespace WindowsServiceTest { public partial class MyNewService : ServiceBase { private readonly EventLog eventLog; private Timer timer; private int eventId = 1; public MyNewService(string[] args) { InitializeComponent(); CanPauseAndContinue = true; eventLog = new EventLog(); if (!EventLog.SourceExists("MySource")) { EventLog.CreateEventSource("MySource", "MyNewLog"); } eventLog.Source = "MySource"; eventLog.Log = "MyNewLog"; eventLog.WriteEntry("Init: " + string.Join(",", args)); } protected override void OnStart(string[] args) { eventLog.WriteEntry("In OnStart: " + string.Join(",", args)); // Set up a timer that triggers every minute. timer = new Timer(); timer.Interval = 60000; // 60 seconds timer.Elapsed += new ElapsedEventHandler(this.OnTimer); timer.Start(); } public void OnTimer(object sender, ElapsedEventArgs args) { eventLog.WriteEntry("Monitoring the System", EventLogEntryType.Information, eventId++); } protected override void OnStop() { eventLog.WriteEntry("In OnStop."); } protected override void OnPause() { timer.Stop(); eventLog.WriteEntry("In OnPause."); } protected override void OnContinue() { timer.Start(); eventLog.WriteEntry("In OnContinue."); } } }
生成服務(wù)程序
在 解決方案資源管理器 中,右鍵項目名選擇 生成 。( Ctrl + B )
已啟動生成…
1>------ 已啟動生成: 項目: WindowsServiceTest, 配置: Debug Any CPU ------
1> WindowsServiceTest -> C:\Users\test\source\repos\WindowsServiceTest\WindowsServiceTest\bin\Debug\WindowsServiceTest.exe
========== 生成: 成功 1 個,失敗 0 個,最新 0 個,跳過 0 個 ==========
生成的 exe 文件默認(rèn)是不能直接運行的( 可以修改 ),需要注冊為服務(wù)才行。

安裝服務(wù)
可以使用通用的 sc 命令進行注冊,就是詳細(xì)配置會繁瑣一點。
:: 注意等號與值中間有個空格
sc create MyNewServiceSC binpath= "C:\Users\test\source\repos\WindowsServiceTest\WindowsServiceTest\bin\Debug\WindowsServiceTest.exe"
也可以按教程中的方法:
添加安裝程序
在 解決方案資源管理器 中,右鍵服務(wù)名( MyNewService.cs ) 查看設(shè)計器 ,在 設(shè)計器 窗口中右鍵 添加安裝程序 。

修改執(zhí)行用戶
選中 serviceProcessInstaller1 ,在 屬性 中修改 Account 為 LocalSystem 。
這個就是任務(wù)管理器中看到的進程所屬的用戶,涉及到權(quán)限的問題。( 參考 )

修改服務(wù)配置( 可選 )
選中 serviceInstaller1 ,在 屬性 中修改服務(wù)名稱、顯示名稱、描述等。
不修改就是默認(rèn)的 Service1 。

重新生成服務(wù)程序( Ctrl + B )使安裝配置生效。
打開 開發(fā)者命令提示

執(zhí)行安裝命令
cd WindowsServiceTest\bin\Debug
:: 需要管理員權(quán)限
installutil WindowsServiceTest.exe
:: 卸載
installutil.exe /u WindowsServiceTest.exe
啟動服務(wù)
任務(wù)管理器 > 服務(wù) > 隨便選中一個服務(wù)右鍵 > 打開服務(wù)

驗證結(jié)果
Win + X> 事件查看器 > 應(yīng)用程序和服務(wù)日志 > MyNewLog
看不到 MyNewLog 需要先啟動服務(wù)后再重新打開 事件查看器 。

因為通用邏輯都封裝在 ServiceBase 里面了,只需要添加自己的業(yè)務(wù)代碼,比起 C++ 實現(xiàn)的 demo 要簡單很多。編寫 多線程服務(wù) 或者復(fù)雜應(yīng)用時可能會遇到一些問題( 參考 )。
參考文章
- 了解 Windows 服務(wù)體系結(jié)構(gòu)
- 后臺服務(wù)程序開發(fā)模式
- 用 C 語言編寫 Windows 服務(wù)程序的五個步驟
- Windows 操作系統(tǒng)的體系結(jié)構(gòu)
- Windows 服務(wù)編寫原理及探討 (1) 、 (2) 、 (3) 、 (4)
- 解決“指定的服務(wù)已經(jīng)標(biāo)記為刪除”問題
結(jié)語
以上內(nèi)容是我根據(jù)日常使用經(jīng)驗再結(jié)合有限的資料整理而成,難免有錯誤的地方,歡迎指正。相關(guān)內(nèi)容比較多,全部引用太占篇幅了,感興趣的話就多點點文中給出的外鏈。
