日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++后台服务程序开发模式

發布時間:2025/3/21 c/c++ 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++后台服务程序开发模式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一直感覺VC++太復雜了,但昨天看了汪蒲陽編著的因特網應用編程,其中寫到后臺服務程序的編寫,論述的非常詳細,而且邏輯清晰,看了之后感覺明白不少,故拿來與需要之人共享,并更正了原程序的一些錯誤,補充了一些材料。另外還有一種用C++編寫后臺服務程序的思路(不算.NET上服務程序開發模型),以后整理好了再發上來。

?

在2000/XP等基于NT 的操作系統中,有一個服務管理器,它管理的后臺進程被稱為 service。

服務是一種應用程序類型,它在后臺運行,與 UNIX 后臺應用程序類似。服務應用程序通常可以

在本地和通過網絡為用戶提供一些功能,例如客戶端/服務器應用程序、Web 服務器、數據庫服

務器以及其他基于服務器的應用程序。

??? 后臺服務 程序是在后臺悄悄運行的。我們通過將自己的程序登記為服務,可以使自己的程序不出現

在任務管理器中,并且隨系統啟動而最先運行,隨系統關閉而最后停止。

????

???? 服務控制管理器是一個RPC 服務器,它顯露了一組應用編程接口,程序員可以方便的編寫程序來配置

服務和控制遠程服務器中服務程序。

???? 服務程序通常編寫成控制臺類型的應用程序,總的來說,一個遵守服務控制管理程序接口要求的程序

包含下面三個函數:

1、服務程序主函數(main):調用系統函數 StartServiceCtrlDispatcher 連接程序主線程到服務控制管理程序。

2、服務入口點函數(ServiceMain):執行服務初始化任務,同時執行多個服務的服務進程有多個服務入口函數。

3、控制服務處理程序函數(Handler):在服務程序收到控制請求時由控制分發線程引用。(此處是Service_Ctrl)。

?另外在系統運行此服務之前需要安裝登記服務程序:installService 函數。刪除服務程序則需要先刪除服務安裝登記:removeService 函數。

?

服務類型:

類型說明SERVICE_FILE_SYSTEM_DRIVER=2文件系統驅動服務。SERVICE_KERNEL_DRIVER=1驅動服務。SERVICE_WIN32_OWN_PROCESS=16獨占一個進程的服務。SERVICE_WIN32_SHARE_PROCESS=32與其他服務共享一個進程的服務。 ?

新建WIN32控制臺程序, 其源文件名為service.cpp 。我用的開發工具是VC++.NET。

?1.服務程序主函數

??? 服務控制管理程序啟動服務程序后,等待服務程序主函數調用系統函StartServiceCtrlDispatcher。一個SERVICE_WIN32_OWN_PROCESS 類型的服務應該立即調用 StartServiceCtrlDispatcher 函數,可以在服務啟動后讓服務入口點函數完成初始化工作。對于 SERVICE_WIN32_OWN_PROCESS 類型的服務和程序中所有服務共同的初始化工作可以在主函數中完成,但不要超過30秒。否則必須建立另外的線程完成這些共同的初始化工作,從而保證服務程序主函數能及時地調用 StartServiceCtrlDispatcher 函數。

?

?

?

?

[cpp] view plaincopy
  • //服務程序主函數。??
  • ??
  • #include?"stdafx.h"??
  • ??
  • #include?"Windows.h"??
  • ??
  • #define?SZAPPNAME??????"serverSample"?????//服務程序名??
  • ??
  • #define?SZSERVICENAME??"serviceSample"????//標識服務的內部名??
  • ??
  • ???
  • ??
  • //內部變量??
  • ??
  • bool???????????????????bDebugServer=false;??
  • ??
  • SERVICE_STATUS??????????????ssStatus;??
  • ??
  • SERVICE_STATUS_HANDLE??sshStatusHandle;??
  • ??
  • DWORD???????????????????????dwErr=0;??
  • ??
  • TCHAR???????????????????????szErr[256];??
  • ??
  • ???
  • ??
  • //下面的函數由程序實現??
  • ??
  • void??WINAPI??Service_Main(DWORD?dwArgc,?LPTSTR?*lpszArgv);??
  • ??
  • void??WINAPI??Service_Ctrl(DWORD?dwCtrlCode);??
  • ??
  • void?installService();??
  • ??
  • void?removeService();??
  • ??
  • void?debugService(int?argc,char**?argv);??
  • ??
  • bool?ReportStatusToSCMgr(DWORD?dwCurrentState,DWORD?dwWin32ExitCode,DWORD?dwWaitHint);??
  • ??
  • void?AddToMessageLog(LPTSTR?lpszMsg);??
  • ??
  • ???
  • ??
  • int?_tmain(int?argc,?_TCHAR*?argv[])??
  • ??
  • {??????
  • ??
  • ?????SERVICE_TABLE_ENTRY?dispatchTable[]=??
  • ??
  • ?????{??
  • ??
  • ?????????{TEXT(SZSERVICENAME),(LPSERVICE_MAIN_FUNCTION)Service_Main},??
  • ??
  • ?????????{?NULL,NULL}??
  • ??
  • ?????};??
  • ??
  • ?????if((argc>1)&&((*argv[1]=='-')||(argv[1]=="/")))??
  • ??
  • ?????{??
  • ??
  • ?????????if(_stricmp("install",argv[1]+1)==0)??
  • ??
  • ?????????{??
  • ??
  • ??????????????installService();??
  • ??
  • ?????????}??
  • ??
  • ?????????else?if(_stricmp("remove",argv[1]+1)==0)??
  • ??
  • ?????????{??
  • ??
  • ??????????????removeService();??
  • ??
  • ?????????}??
  • ??
  • ?????????else?if(_stricmp("debug",argv[1]+1)==0)??
  • ??
  • ?????????{??
  • ??
  • ??????????????bDebugServer=true;??
  • ??
  • ??????????????debugService(argc,argv);??
  • ??
  • ?????????}??
  • ??
  • ?????????else??
  • ??
  • ?????????{????????//如果未能和上面的如何參數匹配,則可能是服務控制管理程序來啟動該程序。立即調用??
  • ??
  • ???????????????????//StartServiceCtrlDispatcher?函數。??
  • ??
  • ??????????????printf("%s?-?install?to?install?the?service?/n",SZAPPNAME);??
  • ??
  • ??????????????printf("%s?-?remove?to?remove?the?service?/n",SZAPPNAME);??
  • ??
  • ??????????????printf("%s?-?debug?to?debug?the?service?/n",SZAPPNAME);??
  • ??
  • ??????????????printf("/n?StartServiceCtrlDispatcher?being?called./n");??
  • ??
  • ??????????????printf("This?may?take?several?seconds.Please?wait./n");??
  • ??
  • ??????????????if(!StartServiceCtrlDispatcher(dispatchTable))??
  • ??
  • ???????????????????AddToMessageLog(TEXT("StartServiceCtrlDispatcher?failed."));??
  • ??
  • ??????????????else??
  • ??
  • ???????????????????AddToMessageLog(TEXT("StartServiceCtrlDispatcher?OK."));??
  • ??
  • ?????????}??
  • ??
  • ?????????exit(0);??
  • ??
  • ?????}??
  • ??
  • ?????return?0;??
  • ??
  • }??
  • ?

    ?

    ?2.服務入口點函數

    ?

    服務入口點函數 service_main 首先調用系統函數 RegisterServiceCtrlHandler 注冊服務控制處理函數 service_ctrl,然后調用 ReportStatusToSCMgr 函數,它通過系統函數 SetServiceStatus 更新服務的狀態,然后調用特定的服務初始化入口函數 ServiceStart 完成具體的初始化工作。

    ?

    [c-sharp] view plaincopy
  • //服務入口點函數??
  • ??
  • void?ServiceStart(DWORD?dwArgc,LPTSTR*?lpszArgv);//具體服務的初始化入口函數??
  • ?void??WINAPI??Service_Main(DWORD?dwArgc,?LPTSTR?*lpszArgv)??
  • ??
  • {??
  • ??
  • ?????//注冊服務控制處理函數??
  • ??
  • ?????sshStatusHandle=RegisterServiceCtrlHandler(TEXT(SZSERVICENAME),Service_Ctrl);??
  • ??
  • ?????//如果注冊失敗??
  • ??
  • ?????if(!sshStatusHandle)??
  • ??
  • ?????{??
  • ??
  • ?????????goto?cleanup;??
  • ??
  • ?????????return;??
  • ??
  • ?????}??
  • ??
  • ?????//初始化?SERVICE_STATUS?結構中的成員??
  • ??
  • ?????ssStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS;??
  • ??
  • ?????ssStatus.dwServiceSpecificExitCode=0;??
  • ??
  • ?????//更新服務狀態??
  • ??
  • ?????if(!ReportStatusToSCMgr(??
  • ??
  • ?????????SERVICE_START_PENDING,//服務狀態,The?service?is?starting.??
  • ??
  • ?????????NO_ERROR,????????????//退出碼???????????
  • ??
  • ?????????3000))???????????????????//等待時間??
  • ??
  • ?????????goto?cleanup;????????//更新服務狀態失敗則轉向?cleanup??
  • ??
  • ?????ServiceStart(dwArgc,lpszArgv);??
  • ??
  • ?????return;??
  • ??
  • cleanup:??
  • ??
  • ?????//把服務狀態更新為?SERVICE_STOPPED,并退出。??
  • ??
  • ?????if(sshStatusHandle)??
  • ??
  • ?????????(void)ReportStatusToSCMgr(SERVICE_STOPPED,dwErr,0);??
  • ??
  • }??
  • ??

    ?

    ?

    ?

    3.控制處理程序函數

    ? 函數 Service_Ctrl 是服務的控制處理程序函數,由主函數線程的控制分發程序引用。在處理控制請求碼時,應該在確定的時間間隔內更新服務狀態檢查點,避免發生服務不能響應的錯誤。

    ?

    [c-sharp] view plaincopy
  • //控制處理程序函數??
  • ??
  • void?WINAPI?Service_Ctrl(DWORD?dwCtrlCode)??
  • ??
  • {??
  • ??
  • ?????//處理控制請求碼??
  • ??
  • ?????switch(dwCtrlCode)??
  • ??
  • ?????{??
  • ??
  • ?????????//先更新服務狀態為?SERVICDE_STOP_PENDING,再停止服務。??
  • ??
  • ?????case?SERVICE_CONTROL_STOP:??
  • ??
  • ?????????ReportStatusToSCMgr(SERVICE_STOP_PENDING,NO_ERROR,500);??
  • ??
  • ?????????ServiceStop();?????//由具體的服務程序實現??
  • ??
  • ?????????return;??
  • ??
  • ?????????//暫停服務??
  • ??
  • ?????case?SERVICE_CONTROL_PAUSE:??
  • ??
  • ?????????ReportStatusToSCMgr(SERVICE_STOP_PENDING,NO_ERROR,500);??
  • ??
  • ?????????ServicePause();????//由具體的服務程序實現??
  • ??
  • ?????????ssStatus.dwCurrentState=SERVICE_PAUSED;??
  • ??
  • ?????????return;??
  • ??
  • ?????????//繼續服務??
  • ??
  • ?????case?SERVICE_CONTROL_CONTINUE:??
  • ??
  • ?????????ReportStatusToSCMgr(SERVICE_STOP_PENDING,NO_ERROR,500);??
  • ??
  • ?????????ServiceContinue();?//由具體的服務程序實現??
  • ??
  • ?????????ssStatus.dwCurrentState=SERVICE_RUNNING;??
  • ??
  • ?????????return;??
  • ??
  • ?????????//更新服務狀態??
  • ??
  • ?????case?SERVICE_CONTROL_INTERROGATE:??
  • ??
  • ?????????break;??
  • ??
  • ?????????//無效控制碼??
  • ??
  • ?????default:??
  • ??
  • ?????????break;??
  • ??
  • ?????}??
  • ??
  • ?????ReportStatusToSCMgr(ssStatus.dwCurrentState,NO_ERROR,0);??
  • ??
  • }??
  • ???
  • ??

    ?

    ?

    ?

    除了系統定義的五種控制碼外(還有一種是:SERVICE_CONTROL_SHUTDOWN),用戶還可自定義控制碼,其取值范圍是128-255。用戶可以通過控制面板中的服務項向特定服務程序的控制處理函數發送控制碼,程序員可以調用系統函數 ControlService 直接向服務程序的控制處理函數發送控制碼。其函數原型如下:

    ?

    [c-sharp] view plaincopy
  • BOOL?ControlService(??
  • ??
  • ??SC_HANDLE?hService,??
  • ??
  • ??DWORD?dwControl,??
  • ??
  • ??LPSERVICE_STATUS?lpServiceStatus??
  • ??
  • );??
  • hService :函數 OpenService or CreateService 返回的服務程序句柄。

    dwControl :控制碼,不能是SERVICE_CONTROL_SHUTDOWN。

    lpServiceStatus:返回最后收到的服務狀態信息。

    ?

    4.安裝服務程序

    ?

    ??? 每個已安裝服務程序在 HKEY_LOCAL_MACHINE/SYSTE/CurrentControlSet/Services 下都有一個服務名的關鍵字,程序員可以調用系統函數 CreateService 安裝服務程序,并指定服務類型,服務名等。這個函數創建一個服務對象,并將其增加到相關的服務控制管理器數據庫中。

    下面是函數原型:

    [cpp] view plaincopy
  • ???
  • ??
  • SC_HANDLE?CreateService(??
  • ??
  • ??SC_HANDLE?hSCManager,?//服務控制管理程序維護的登記數據庫的句柄,由系統函數OpenSCManager?返回???
  • ??
  • ??LPCTSTR?lpServiceName,?//以NULL?結尾的服務名,用于創建登記數據庫中的關鍵字??
  • ??
  • ??LPCTSTR?lpDisplayName,?//以NULL?結尾的服務名,用于用戶界面標識服務??
  • ??
  • ??DWORD?dwDesiredAccess,?//指定服務返回類型??
  • ??
  • ??DWORD?dwServiceType,?//指定服務類型??
  • ??
  • ??DWORD?dwStartType,?//指定何時啟動服務??
  • ??
  • ??DWORD?dwErrorControl,?//指定服務啟動失敗的嚴重程度??
  • ??
  • ??LPCTSTR?lpBinaryPathName,?//指定服務程序二進制文件的路徑??
  • ??
  • ??LPCTSTR?lpLoadOrderGroup,?//指定順序裝入的服務組名??
  • ??
  • ??LPDWORD?lpdwTagId,?//忽略,NULL??
  • ??
  • ??LPCTSTR?lpDependencies,?//指定啟動該服務前必須先啟動的服務或服務組??
  • ??
  • ??LPCTSTR?lpServiceStartName,?//以NULL?結尾的字符串,指定服務帳號。如是NULL,則表示使用LocalSystem?帳號??
  • ??
  • ??LPCTSTR?lpPassword?//以NULL?結尾的字符串,指定對應的口令。為NULL表示無口令。但使用LocalSystem時填NULL??
  • ??
  • );??
  • ?

    ???? 對于一個已安裝的服務程序,可以調用系統函數 OpenService 來獲取服務程序的句柄

    下面是其函數原型:

    [c-sharp] view plaincopy
  • SC_HANDLE?OpenService(??
  • ??
  • ??SC_HANDLE?hSCManager,??
  • ??
  • ??LPCTSTR?lpServiceName,??
  • ??
  • ??DWORD?dwDesiredAccess??
  • ??
  • );??
  • ?

    hSCManager :服務控制管理程序微服的登記數據庫的句柄。由函數 OpenSCManager function 返回 這個句柄。

    lpServiceName :將要打開的以NULL 結尾的服務程序的名字,和 CreateService? 中的 lpServiceName 相對應。

    dwDesiredAccess :指定服務的訪問類型。服務響應請求時,首先檢查訪問類型。

    用CreateService 或OpenService 打開的服務程序句柄使用完畢后必須用CloseServiceHandle 關閉。

    OpenSCManager打開的服務管理數據庫句柄也必須用它來關閉。

    ?

    ?

    [cpp] view plaincopy
  • //安裝服務程序??
  • ??
  • void?installService()??
  • ??
  • {??
  • ??
  • ?????SC_HANDLE?schService;??
  • ??
  • ?????SC_HANDLE?schSCManager;??
  • ??
  • ?????TCHAR?szPath[512];??
  • ??
  • ?????//得到程序磁盤文件的路徑??
  • ??
  • ?????if(GetModuleFileName(NULL,szPath,512)==0)??
  • ??
  • ?????{??
  • ??
  • ?????????_tprintf(TEXT("Unable?to?install?%s?-?%s?/n"),??
  • ??
  • ??????????????TEXT(SZAPPNAME),??
  • ??
  • ?????????GetLastError());//@1獲取調用函數返回的最后錯誤碼??
  • ??
  • ?????????return;??
  • ??
  • ?????}??
  • ??
  • ?????//打開服務管理數據庫??
  • ??
  • ?????schSCManager=OpenSCManager(??
  • ??
  • ????????????????????????????NULL,????//本地計算機??
  • ??
  • ????????????????????????????NULL,????//默認的數據庫??
  • ??
  • ????????????????????????????SC_MANAGER_ALL_ACCESS??//要求所有的訪問權??
  • ??
  • ????????????????????????????);??
  • ??
  • if(schSCManager)??
  • ??
  • ?????{??
  • ??
  • ?????????//登記服務程序??
  • ??
  • ?????????schService=CreateService(??
  • ??
  • ??????????????schSCManager,????????????????????//服務管理數據庫句柄??
  • ??
  • ??????????????TEXT(SZSERVICENAME),?????????????//服務名??
  • ??
  • ??????????????TEXT(SZAPPNAME),???????//用于顯示服務的標識??
  • ??
  • ??????????????SERVICE_ALL_ACCESS,??????????????//響應所有的訪問請求??
  • ??
  • ??????????????SERVICE_WIN32_OWN_PROCESS,???????//服務類型??
  • ??
  • ??????????????SERVICE_DEMAND_START,????????????//啟動類型??
  • ??
  • ??????????????SERVICE_ERROR_NORMAL,????????????//錯誤控制類型??
  • ??
  • ??????????????szPath,??????????????????????????????//服務程序磁盤文件的路徑??
  • ??
  • ??????????????NULL,????????????????????????????????//服務不屬于任何組??
  • ??
  • ??????????????NULL,????????????????????????????????//沒有tag標識符??
  • ??
  • ??????????????NULL,??????????????//啟動服務所依賴的服務或服務組,這里僅僅是一個空字符串??
  • ??
  • ??????????????NULL,????????????????????????????????//LocalSystem?帳號??
  • ??
  • ??????????????NULL);??
  • ??
  • ?????????if(schService)??
  • ??
  • ?????????{??
  • ??
  • ??????????????_tprintf(TEXT("%s?installed.?/n"),TEXT(SZAPPNAME));??
  • ??
  • ??????????????CloseServiceHandle(schService);??
  • ??
  • ?????????}??
  • ??
  • ?????????else??
  • ??
  • ?????????{??
  • ??
  • ??????????????_tprintf(TEXT("CreateService?failed?-?%s?/n"),GetLastError());??
  • ??
  • ?????????}??
  • ??
  • ?????????CloseServiceHandle(schSCManager);??
  • ??
  • ?????}??
  • ??
  • ?????else??
  • ??
  • ?????????_tprintf(TEXT("OpenSCManager?failed?-?%s?/n"),GetLastError());??
  • ??
  • }??
  • ???
  • ?

    ?

    ?

    主函數處理了三中命令行參數:- install,- remove,- debug,分別用于安裝,刪除和調試服務程序。如果不帶參數運行,則認為是服務控制管理出現啟動該服務程序。參數不正確則給出提示信息。

    ?

    StartServiceCtrlDispatcher 函數負責把程序主線程連接到服務控制管理程序。具體描述如下:

    BOOL StartServiceCtrlDispatcher(

    ? const LPSERVICE_TABLE_ENTRY lpServiceTable);

    lpServiceStartTable 指向 SERVICE_TABLE_ENTRY 結構類型的數組,他包含了調用進程所提供的每個服務的入口函數和字符串名。表中的最后一個元素必須為 NULL,指明入口表結束。SERVICE_TABLE_ENTRY 結構具體描述如下:

    ?

    typedef struct _SERVICE_TABLE_ENTRY {? LPTSTR lpServiceName;? LPSERVICE_MAIN_FUNCTION lpServiceProc;

    } SERVICE_TABLE_ENTRY, *LPSERVICE_TABLE_ENTRY;

    ?

    lpServiceName 是一個以 NULL 結尾的字符串,標識服務名。如果是 SERVICE_WIN32_OWN_PROCESS 類型的服務,這個字符串會被忽略。

    lpServiceProc 指向服務入口點函數。

    ?

    本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/camforg2010/archive/2010/04/20/5505171.aspx

    總結

    以上是生活随笔為你收集整理的C++后台服务程序开发模式的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。