中國(guó)電建集團(tuán)華東勘測(cè)設(shè)計(jì)研究院有限公司 黃成家 李增煥 楊磊
根據(jù)Windows服務(wù)器中的網(wǎng)站系統(tǒng)運(yùn)維和開(kāi)發(fā)工作需求,開(kāi)發(fā)并實(shí)現(xiàn)了Windows系統(tǒng)下方便適用且非常輕量的系統(tǒng)服務(wù)注冊(cè)及管理軟件,克服了常規(guī)應(yīng)用程序無(wú)法注冊(cè)為合規(guī)的Windows系統(tǒng)服務(wù)的限制,可將任意的應(yīng)用程序注冊(cè)為系統(tǒng)服務(wù),由此簡(jiǎn)化了Windows服務(wù)器中的網(wǎng)站或其他服務(wù)的開(kāi)發(fā)、部署及更新工作。
為應(yīng)對(duì)服務(wù)器非正常重啟等異常狀況,網(wǎng)站服務(wù)、API服務(wù)或其他類(lèi)似應(yīng)用程序需要隨系統(tǒng)開(kāi)機(jī)自動(dòng)運(yùn)行。Linux系統(tǒng)下,采用service或systemd命令可以非常簡(jiǎn)便地將任意的應(yīng)用程序注冊(cè)為系統(tǒng)服務(wù),實(shí)現(xiàn)應(yīng)用程序隨系統(tǒng)開(kāi)機(jī)自動(dòng)運(yùn)行[1]。然而,Windows系統(tǒng)下卻缺少類(lèi)似的工具或軟件,給Windows服務(wù)器的運(yùn)維和管理人員帶來(lái)了不便。
本文作者利用.Net Framework開(kāi)發(fā)并實(shí)現(xiàn)了方便適用且非常輕量的系統(tǒng)服務(wù)注冊(cè)及管理軟件,引入中間二進(jìn)制程序,克服了常規(guī)應(yīng)用程序無(wú)法注冊(cè)為合規(guī)的系統(tǒng)服務(wù)的限制,可將任意應(yīng)用程序注冊(cè)為系統(tǒng)服務(wù),由此簡(jiǎn)化了Windows服務(wù)器下的網(wǎng)站或其他服務(wù)的開(kāi)發(fā)、部署及更新工作。
Windows系統(tǒng)下,將應(yīng)用程序設(shè)置為隨開(kāi)機(jī)自動(dòng)啟動(dòng)的現(xiàn)有方案主要有以下5種方法:
(1)修改注冊(cè)表中的啟動(dòng)項(xiàng);(2)將應(yīng)用程序的快捷方式復(fù)制到啟動(dòng)目錄下;(3)創(chuàng)建隨開(kāi)機(jī)啟動(dòng)的計(jì)劃任務(wù);(4)用sc命令將應(yīng)用程序注冊(cè)為系統(tǒng)服務(wù);(5)用第三方工具(NSSM或類(lèi)似工具)將應(yīng)用程序注冊(cè)為系統(tǒng)服務(wù)。
其中前兩種方式均需用戶(hù)登陸成功后才能運(yùn)行,需要人工的介入,不適合系統(tǒng)重啟后需要自動(dòng)運(yùn)行的應(yīng)用程序(如網(wǎng)站服務(wù)或數(shù)據(jù)庫(kù)服務(wù)等)。
創(chuàng)建計(jì)劃任務(wù)可實(shí)現(xiàn)應(yīng)用程序隨開(kāi)機(jī)自動(dòng)啟動(dòng),但是創(chuàng)建過(guò)程較為繁瑣,且應(yīng)用程序需要更新時(shí)也不方便。
采用系統(tǒng)自帶的sc命令可實(shí)現(xiàn)系統(tǒng)服務(wù)的注冊(cè)和啟動(dòng),但是應(yīng)用程序必須是可執(zhí)行的二進(jìn)制程序,且必須按照微軟的服務(wù)程序格式編寫(xiě),在程序內(nèi)部實(shí)現(xiàn)一個(gè)特定的消息響應(yīng)循環(huán),否則,用sc命令注冊(cè)為系統(tǒng)服務(wù)后,服務(wù)無(wú)法正常啟動(dòng)[2-5]。事實(shí)上,絕大多數(shù)常規(guī)應(yīng)用程序都無(wú)法用sc命令注冊(cè)為合規(guī)的系統(tǒng)服務(wù)。
采用NSSM或類(lèi)似第三方工具將常規(guī)應(yīng)用程序注冊(cè)為系統(tǒng)服務(wù)是目前來(lái)說(shuō)較為可行的解決方案,但是也存在命令行操作方式復(fù)雜、缺少日志管理功能、無(wú)退出通知機(jī)制等缺點(diǎn)。
系統(tǒng)運(yùn)維工作中,網(wǎng)站服務(wù)、API服務(wù)或其他長(zhǎng)期運(yùn)行的服務(wù)類(lèi)應(yīng)用程序都有以下共性的需求:
(1)程序需要在后臺(tái)長(zhǎng)期運(yùn)行,即便用戶(hù)注銷(xiāo)仍不停止。(2)系統(tǒng)開(kāi)機(jī)或重啟后,程序被自動(dòng)啟動(dòng)。(3)程序意外停止時(shí),程序被自動(dòng)重新啟動(dòng)。(4)程序可能依賴(lài)于其他服務(wù),啟動(dòng)之前需要先等待相關(guān)服務(wù)啟動(dòng)完成。(5)程序應(yīng)能隨時(shí)被用戶(hù)停止或重啟,以方便對(duì)服務(wù)進(jìn)行更新。
根據(jù)以上需求,結(jié)合Windows系統(tǒng)服務(wù)提供的功能,并考慮操作簡(jiǎn)便的要求,整理本軟件需要提供的命令及功能如下:
用戶(hù)將應(yīng)用程序的命令行參數(shù)、工作目錄、程序輸出目錄、輸出編碼,以及需注冊(cè)的系統(tǒng)服務(wù)名稱(chēng)、服務(wù)依賴(lài)等信息保存在配置文件中。
注冊(cè)并啟動(dòng)一個(gè)自啟動(dòng)的系統(tǒng)服務(wù),服務(wù)名稱(chēng)等信息由配置文件指定,該服務(wù)啟動(dòng)時(shí)會(huì)去啟動(dòng)配置文件中指定的應(yīng)用程序。同時(shí),該服務(wù)會(huì)在系統(tǒng)開(kāi)機(jī)時(shí)等待相關(guān)依賴(lài)啟動(dòng)后自動(dòng)啟動(dòng)。
停止并刪除由配置文件中指定的系統(tǒng)服務(wù),該服務(wù)停止時(shí)會(huì)通知并等待應(yīng)用程序退出。
停止、啟動(dòng)或重啟指定的系統(tǒng)服務(wù)。
當(dāng)停止服務(wù),應(yīng)具有通知應(yīng)用進(jìn)程退出、并等待其自行退出的功能。
應(yīng)用程序運(yùn)行過(guò)程的中輸出(寫(xiě)入到標(biāo)準(zhǔn)輸出或標(biāo)準(zhǔn)錯(cuò)誤的數(shù)據(jù))均按日期寫(xiě)入到配置文件中指定的目錄下。
系統(tǒng)服務(wù)的運(yùn)行過(guò)程中,對(duì)應(yīng)用程序進(jìn)程進(jìn)行監(jiān)視,如果發(fā)現(xiàn)該進(jìn)程已退出或占用內(nèi)存超過(guò)指定值,則重新啟動(dòng)應(yīng)用程序。
軟件采用C#語(yǔ)言編寫(xiě),基于.NetFramework 4.0框架[6-7],開(kāi)發(fā)環(huán)境采用Visual Studio Community 2019。
由于常規(guī)的應(yīng)用程序無(wú)法注冊(cè)為系統(tǒng)服務(wù),因此,軟件本身采用微軟要求的服務(wù)程序格式要求編制,在程序內(nèi)部實(shí)現(xiàn)服務(wù)消息循環(huán)。在調(diào)用軟件的install命令時(shí),該命令會(huì)將軟件自身的二進(jìn)制可執(zhí)行文件注冊(cè)為系統(tǒng)服務(wù)。而軟件作為系統(tǒng)服務(wù)被啟動(dòng)時(shí),會(huì)啟動(dòng)一個(gè)子進(jìn)程去運(yùn)行配置文件中指定的應(yīng)用程序;該軟件作為系統(tǒng)服務(wù)被停止時(shí),會(huì)通知子進(jìn)程退出并在必要的情況下直接終止子進(jìn)程。按此方式,便繞過(guò)了常規(guī)應(yīng)用程序無(wú)法注冊(cè)為系統(tǒng)服務(wù)的限制,實(shí)現(xiàn)了任意應(yīng)用程序隨開(kāi)機(jī)自動(dòng)啟動(dòng)、并按系統(tǒng)服務(wù)模式隨時(shí)停止或重啟。
根據(jù)上述方式,軟件有服務(wù)管理模式和服務(wù)運(yùn)行模式兩種運(yùn)行模式。其中服務(wù)管理模式下,軟件執(zhí)行install|remove|stop|start|restart等命令,讀取配置文件中指定的服務(wù)信息,調(diào)用sc create命令將自身的二進(jìn)制可執(zhí)行文件注冊(cè)為系統(tǒng)服務(wù),或調(diào)用sc delete命令刪除已注冊(cè)的系統(tǒng)服務(wù),同時(shí)利用.Net Framework提供的ServiceController類(lèi)對(duì)已注冊(cè)的系統(tǒng)服務(wù)進(jìn)行停止或啟動(dòng)等操作。而在服務(wù)運(yùn)行模式下,軟件的作為系統(tǒng)服務(wù)的執(zhí)行程序,被Windows系統(tǒng)的服務(wù)管理器控制,響應(yīng)系統(tǒng)傳來(lái)的啟動(dòng)或停止等控制消息,并啟動(dòng)、監(jiān)視或停止應(yīng)用程序的運(yùn)行。
軟件內(nèi)部運(yùn)行流程分別見(jiàn)圖1、圖2和圖3。
圖1 軟件總體運(yùn)行流程Fig.1 The overall running procedure of the software
圖2 服務(wù)運(yùn)行模式內(nèi)部運(yùn)行流程Fig.2 The running procedure of service-runner mode
圖3 服務(wù)管理模式內(nèi)部運(yùn)行流程Fig.3 The running procedure of service-manager mode
在服務(wù)管理模式下,軟件由用戶(hù)在命令行終端運(yùn)行,因此配置文件直接使用當(dāng)前工作目錄下的特定文件(svc.conf)。
而在服務(wù)運(yùn)行模式下,情況比較復(fù)雜,因?yàn)檐浖蒞indows 系統(tǒng)的服務(wù)管理器啟動(dòng),當(dāng)前工作目錄為系統(tǒng)目錄,不是用戶(hù)存放配置文件的目錄。因此,本軟件采用了以下策略來(lái)定位配置文件:
(1)注冊(cè)服務(wù)時(shí)(此時(shí)在服務(wù)管理模式下),將配置文件路徑保存在系統(tǒng)服務(wù)的Discription中。(2)服務(wù)運(yùn)行模式下,首先根據(jù)本進(jìn)程ID查找到本服務(wù)的ServiceName,再根據(jù)Service-Name獲取本服務(wù)的Discription,由此便可得到配置文件路徑。
以下以一個(gè)簡(jiǎn)單的Node.js程序?yàn)槔?,說(shuō)明本軟件的使用方法。
示例應(yīng)用程序采用Node.js編寫(xiě),其功能僅僅是每隔1秒打印一行信息,且鍵入回車(chē)后退出,程序代碼如下:
將軟件自帶文件拷貝到任意位置,右鍵單擊bin目錄下的register-this-path.bat,以管理員身份運(yùn)行,將bin目錄加入至系統(tǒng)路徑中,也可以手動(dòng)將此目錄加入至系統(tǒng)路徑。
重新打開(kāi)“我的電腦”,在任意位置打開(kāi)一個(gè)命令行窗口,輸入svc-v,如果正常輸出版本信息,則表明安裝成功。
打開(kāi)命令行窗口,輸入svc create hello-svc,將創(chuàng)建一個(gè)工程hello-svc。將示例程序index.js拷貝到hellosvc/worker目錄下。打開(kāi)hello-svc/svc.conf文件,輸入以下內(nèi)容:
用管理員身份打開(kāi)命令行窗口(Win10系統(tǒng)下,需要在開(kāi)始菜單中搜索cmd然后右鍵以管理員身份運(yùn)行),cd到hello-svc目錄:
(1)運(yùn)行svc check命令檢查配置是否合法。(2)運(yùn)行svc test-worker命令測(cè)試應(yīng)用程序是否能正常運(yùn)行。
若配置和應(yīng)用程序無(wú)誤,則:
(3)運(yùn)行svc install命令安裝并啟動(dòng)系統(tǒng)服務(wù),此時(shí)應(yīng)用程序就已經(jīng)開(kāi)始在后臺(tái)運(yùn)行了;
(4)運(yùn)行svc log查看正在運(yùn)行的服務(wù)程序的輸出;
(5)運(yùn)行svc stop|start|restart|remove停止、啟動(dòng)、重啟或刪除本系統(tǒng)服務(wù)。
在系統(tǒng)重啟、用戶(hù)注銷(xiāo)等情況下,用ssh遠(yuǎn)程連接系統(tǒng),cd到hello-svc目錄,運(yùn)行svc log查看程序輸出,確認(rèn)應(yīng)用程序一直在運(yùn)行。
按以上步驟,用svc create創(chuàng)建多個(gè)目錄,修改svc.conf中的服務(wù)名和程序名等內(nèi)容,再在這些目錄下打開(kāi)命令行窗口執(zhí)行svc check|test-worker|install等命令可以注冊(cè)多個(gè)服務(wù),這些服務(wù)可使用以下命令進(jìn)行統(tǒng)一管理:
(1)svc list|ls:列出所有服務(wù)的信息及運(yùn)行狀態(tài)。(2)svc start|stop|remove all:啟動(dòng)、停止或刪除所有服務(wù)。(3)svc check|status|test-worker|install|start|stop|restart|remove|log $project-directory:操作$project-directory目錄下svc.conf指定的服務(wù),$project-directory中必須含有字符或/。(4)svc start|stop|restart|remove |log $service-name:操作名稱(chēng)為$service-name的服務(wù)。(5)svc start|stop|restart|remove|log $service-index:操作第$service-index個(gè)服務(wù)(運(yùn)行svc ls可查看所有服務(wù)的序號(hào))。
從應(yīng)用實(shí)例可以看出,本文實(shí)現(xiàn)的軟件可將任意的應(yīng)用程序注冊(cè)為系統(tǒng)服務(wù),克服了常規(guī)應(yīng)用程序無(wú)法注冊(cè)為合規(guī)的Windows系統(tǒng)服務(wù)的限制,與傳統(tǒng)的計(jì)劃任務(wù)或第三方工具方案相比,網(wǎng)站或其他服務(wù)的開(kāi)發(fā)、部署及更新工作大為簡(jiǎn)化,為運(yùn)維工作人員帶來(lái)了很大的便利。軟件自2019年11月發(fā)布在開(kāi)源社區(qū)Github上以來(lái),已被多個(gè)網(wǎng)站引用,并廣受同行的好評(píng)。
數(shù)字技術(shù)與應(yīng)用2021年11期