民航中南空管局氣象中心數(shù)據(jù)庫室 歐壯杰
我們知道,在unix操作系統(tǒng)中,遠程主機命令行程序的運行和進程的關(guān)閉可通過telnet來實現(xiàn),當客戶機裝有x-windows時,可以運行遠程主機圖形界面的程序且界面顯示在客戶機上,相當于延長了遠程主機顯示屏的距離。但windows產(chǎn)品在windows2000以前只有一個叫“八爪魚”的不成熟第三方產(chǎn)品可實現(xiàn)該功能。隨著windows2000的發(fā)布,終端服務(wù)功能成為windows2000的一個亮點,只要在服務(wù)器端和客戶端安裝上相應(yīng)的程序,就可以實現(xiàn)遠程桌面的功能。但是對于要實時監(jiān)控通過慢速的DDN專線連接的遠程主機上的程序,則終端服務(wù)占用了太多的帶寬。因此,我們采用自己編程序的方法,用較少的傳輸量就可以實時監(jiān)控遠程主機的程序。 我們的設(shè)計方法是:在服務(wù)器端運行一個實時進程監(jiān)控程序,定時讀取服務(wù)器進程的運行情況;在客戶端運行一個終端程序,通過服務(wù)器端的進程監(jiān)控程序把服務(wù)器的進程運行情況在終端顯示出來,并可在終端發(fā)送指令指示服務(wù)器啟動和停止特定的進程,甚至重啟遠程主機。 1、服務(wù)器端進程監(jiān)控程序 在windows2000 和windows 95以上的版本中,Microsoft 提供了一套工具幫助函數(shù)(Tool Help),該套函數(shù)用于獲得當前系統(tǒng)中運行的進程、堆、模塊及進程使用的線程的快照集。在windows nt 4.0中是沒有提供。但我們現(xiàn)在的遠程主機都是安裝了windows 2000,因此可在上面運行該套函數(shù),下面是例子(采用delphi 語言): procedure TForm1.Button1Click(Sender: TObject); var i : integer; ContinueLoop:BOOL; FSnapshotHandle:THandle; FProcessEntry32:TProcessEntry32; begin FSnapshotHandle:=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); FProcessEntry32.dwSize:=Sizeof(FProcessEntry32); file://指定結(jié)構(gòu)的大小 ContinueLoop:=Process32First(FSnapshotHandle,FProcessEntry32); while integer(ContinueLoop)<>0 do begin Demo1.Lines.Add(inttostr(FProcessEntry32.th32ProcessID)+ ':'+FProcessEntry32.szExeFile); ContinueLoop:=Process32Next(FSnapshotHandle,FProcessEntry32); end; CloseHandle (FSnapshotHandle); end; 程序中首先調(diào)用CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0)函數(shù)來獲得當前進程快照集的打開句柄。 TProcessEntry32是一個進程入口結(jié)構(gòu),它用于存儲所掃描到的進程信息,如進程號、進程可執(zhí)行文件名字等。第二步就是調(diào)用Process32First(FSnapshotHandle,FProcessEntry32)函數(shù)來尋找第一個進程,當返回值ContinueLoop為True時說明已找到進程;而Process32Next(FSnapshotHandle,FProcessEntry32)用于取得記錄在系統(tǒng)快照集里的下一個進程信息。當返回值為False為說明列舉已完成。TProcessEntry32結(jié)構(gòu)的th32ProcessID屬性記錄了當前進程的進程號;szExeFile屬性記錄了當前進程的可執(zhí)行文件名字;獲得每一進程的這兩個信息,就可以知當前系統(tǒng)的進程運行情況。 當客戶端軟件提出瀏覽遠端進程要求時,服務(wù)器端可運行該段程序并把獲得的信息發(fā)給客戶端。 再有,在windows2000下,可執(zhí)行GetProcessTimes函數(shù)來獲得該進程以內(nèi)核模式已經(jīng)執(zhí)行的時間和以用戶模式已經(jīng)執(zhí)行的時間,這樣我們就可大概了解該進程對CPU的占用情況。以便及時采取相應(yīng)的措施。 當獲得服務(wù)器端進程后,我們在客戶端可發(fā)出指令,讓服務(wù)器端程序終止某一進程或啟動某一程序,用TerminateProcess函數(shù)可結(jié)束指定的進程及其所擁有的線程,該函數(shù)使得一個進程中的所有線程都終止,且引起該進程退出,但進程終止的消息不通知給附加的動態(tài)連接庫DLL,因此使用該函數(shù)不能太頻繁。 我們還可以在服務(wù)器端截取屏幕,并把屏幕存為jpg格式圖像后以數(shù)據(jù)流的方式發(fā)送給客戶端。 另外,為了監(jiān)控服務(wù)器上的進程所占用的內(nèi)存資源,我們可利用 GetProcessMemoryInfo函數(shù)來獲得當前進程所占用內(nèi)存的大小,例子如下: procedure TForm1.Button1Click(Sender: TObject); var hd:HWND; dw:Dword; PMC: PPROCESS_MEMORY_COUNTERS; begin dw:=4294548877;//假設(shè)該數(shù)值為某一進程的進程號 hd:=OpenProcess(PROCESS_TERMINATE,FALSE,dw); file://獲得進程的句柄 PMC.cb:=sizeof(PMC); if GetProcessMemoryInfo(hd, PMC, PMC.cb) then begin file://調(diào)用PMC.WorkingSetSize來獲得所占用內(nèi)存的大小 end; CloseHandle(hd); end; 需要注意的是GetProcessMemoryInfo函數(shù)只在windows nt/2000 下可用,在windows98中沒有函數(shù)可獲得進程內(nèi)存的大小,另外要在uses部分引用PsAPI單元,里面有GetProcessMemoryInfo函數(shù)引用說明。 2、客戶端程序 客戶端的程序比較簡單,主要功能是要實現(xiàn)指令的發(fā)送和信息的接收。 3、程序間的通信 我們采用socket套接字來實現(xiàn)程序間的通信,在服務(wù)器端運行一Socket服務(wù)器序,監(jiān)聽來自客戶端的連接和接受指令。在delphi中,復雜的Socket函數(shù)被封裝成一控件TserverSocket,該控件繼承自TCustomSocket 對象,封裝了對監(jiān)聽端口綁定和監(jiān)聽。只要調(diào)用TserverSocket控件的Open方法,就可使服務(wù)器端的Sockct處于監(jiān)聽狀態(tài),當客戶端有連接請求時將自動接受連接,然后在ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket)事件中讀取來自客戶端的請求。為了安全起見,我們可自定義較高層的協(xié)議,在客端所發(fā)送的信息中加上內(nèi)容標識,如"user:abcdef",表示收到用戶的驗證,然后和客戶端之間進行安全的認證。在讀到數(shù)據(jù)時,我們可根據(jù)內(nèi)容做出相應(yīng)的動作,如取得進程的信息并發(fā)送給客戶。 在客戶端,我們采用TclientSocket控件來同服務(wù)器端進行通信,在指定了服務(wù)器端的IP地址和端口后,調(diào)用Open方法來和服務(wù)端的Socket取得聯(lián)系并發(fā)送用戶名和密碼到服務(wù)端進行驗證,之后就可以發(fā)送指令和接收數(shù)據(jù)了。需要說明的是,客戶發(fā)送的指令要和服務(wù)器端進行商議好。 以上只是一個初步的應(yīng)用,利用該思路還可做得更多,我們在實際應(yīng)用取得了較好的效果。
|