羅偉雄,時東曉,曾紀(jì)霞,劉 嵐
(廣州城市職業(yè)學(xué)院網(wǎng)絡(luò)與教育技術(shù)中心,廣東 廣州 510405)
目前眾多的計算機實驗室管理系統(tǒng)[1-2]都有遠程控制[3]功能,但是只能在同一時間對一臺客戶機進行控制,無法實現(xiàn)并發(fā)式的集中控制,因此在軟件安裝和考前測試時,無法發(fā)揮遠程控制的優(yōu)勢來減輕管理員的工作量。尤其是當(dāng)要輸入不同的賬號等信息時,只能逐臺機器操作,工作量大,操作繁瑣。
而隨著虛擬化技術(shù)的普及,虛擬化云桌面[4-6]也逐步進入計算機實驗室。但是該技術(shù)只能解決系統(tǒng)的安裝、部署等問題,對于考前測試等,需要進行操作和輸入信息的工作,虛擬化云桌面技術(shù)也無能為力。
為此,筆者編寫了一套計算機實驗室并發(fā)式集中遠程控制系統(tǒng)以解決上述問題。
本系統(tǒng)最大的特點是,可以在一臺管理機上同時同步對同一子網(wǎng)內(nèi)的所有客戶機進行遠程控制,而且還可以讓各客戶機自動輸入不同的字符串,實現(xiàn)諸如測試考試軟件時,自動輸入不同賬號的目的。另外系統(tǒng)還提供了同步各個客戶機當(dāng)前活動窗口位置和大小的功能,以達到鼠標(biāo)的精準(zhǔn)定位。同時系統(tǒng)還可以對客戶機進行分組,實現(xiàn)分批控制。除此之外,系統(tǒng)還可以監(jiān)控客戶機的屏幕畫面,實現(xiàn)遠程關(guān)機、重啟等常見的操作。
由于當(dāng)前計算機實驗室以Windows系統(tǒng)居多,因此整套系統(tǒng)是基于Windows環(huán)境設(shè)計和開發(fā)的。系統(tǒng)分為客戶端和管理端兩部分??蛻舳瞬渴鹪诿颗_受控的機器上,管理端部署在管理機上,整個系統(tǒng)不需要安裝,拷貝即可使用。為了提高系統(tǒng)的兼容性,以適應(yīng)從Windows XP版本開始的Windows系列系統(tǒng)的使用,同時為了便于部署,避免依賴JAVA、.NET等框架,系統(tǒng)采用Delphi語言進行開發(fā),以全編譯方式生成原生可執(zhí)行代碼,進一步提高執(zhí)行效率。
系統(tǒng)的實現(xiàn)原理如圖1所示。
圖1 系統(tǒng)原理Fig.1 Sy stem principle
從圖1中可以看到,系統(tǒng)只需一臺管理端即可實現(xiàn)對多臺客戶端的并發(fā)式遠程控制[7],在客戶端群中,需要一臺客戶機作為種子機。由于計算機實驗室的機器其操作系統(tǒng)基本上都是通過克隆來批量安裝的[8],因此不論是屏幕分辨率或者是桌面圖標(biāo)的位置,還是開始菜單上各菜單項的順序都是相同的,而且每次打開相同的窗口其位置和大小也是相同的。因此,只需觀察任意一臺客戶機就可以知道其他客戶機的狀態(tài)。
首先,在客戶端群中任意選取一臺客戶機作為種子機,然后向種子機發(fā)送獲取屏幕截圖指令(圖1中功能 1.1),種子機收到該指令后返回當(dāng)前屏幕截圖給管理端(圖1中功能1.2),管理端收到后,顯示種子機屏幕畫面;當(dāng)需要同步當(dāng)前活動窗口狀態(tài)時,管理端向種子機發(fā)送獲取當(dāng)前活動窗口狀態(tài)指令(圖1中功能2.1),種子機收到指令后獲取當(dāng)前活動窗口狀態(tài)并返回給管理端(圖1中功能2.2),管理端收到返回信息后向客戶端群發(fā)送窗口狀態(tài)同步指令(圖1中功能2.3),各客戶端收到指令后執(zhí)行窗口同步操作;在進行鼠標(biāo)、鍵盤和其他指令的集中操作時,管理端直接向客戶端群發(fā)送相應(yīng)的指令。
向種子機發(fā)送指令時,采用單播方式,而向客戶端群發(fā)送指令時,由于無需等待客戶端返回信息,而且指令又比較短,不需要分塊發(fā)送,加上客戶端比較多,因此適合采用廣播方式進行傳輸。
UDP廣播[9],只需要把信息發(fā)送到廣播地址255.255.255.255上,則同一廣播網(wǎng)絡(luò)上的所有主機都會收到該信息,從而有效提高了發(fā)送效率,減少了對網(wǎng)絡(luò)資源的占用。
而TCP協(xié)議由于是面向連接的,在發(fā)送數(shù)據(jù)前必須與對方建立連接。如果采用TCP協(xié)議,則管理端在發(fā)送數(shù)據(jù)前,必須與每個客戶端建立TCP連接,這樣勢必會消耗大量的時間和資源。另外對于計算機實驗室這樣的局域網(wǎng),一般網(wǎng)絡(luò)通訊質(zhì)量比較高,干擾比較少,使用UDP系統(tǒng)即可滿足需求,因此系統(tǒng)采用UDP廣播方式作為指令的傳輸協(xié)議。
而對于種子機屏幕畫面數(shù)據(jù)的傳輸,由于其數(shù)據(jù)量比較大,因此需要分塊傳送,這就要求傳輸過程中必須要有流量控制、差錯控制和擁塞控制[10]。因此系統(tǒng)選擇TCP作為其傳輸協(xié)議,這樣既可以保證系統(tǒng)的可靠性和穩(wěn)定性,同時也降低了系統(tǒng)開發(fā)的復(fù)雜度,不需要編寫額外的流量控制、差錯控制和擁塞控制等代碼。
系統(tǒng)指令的基本格式為:<命令> [參數(shù) 1|參數(shù)2|…|參數(shù) n]。
命令和第一個參數(shù)之間用空格間隔,各參數(shù)之間用“|”間隔。
考慮到命令的數(shù)量有限,因此規(guī)定命令為3個字符的固定長度。例如,獲取窗口狀態(tài)指令為WIN,鍵盤指令為CMD等。
各參數(shù)之間用“|”間隔的原因是由于在設(shè)置窗口狀態(tài)時,系統(tǒng)是根據(jù)窗口標(biāo)題來查找窗口的,而窗口的標(biāo)題是允許包含空格、逗號、分號等常見的分隔符。因此如果使用這些常見的符號作為分隔符就會導(dǎo)致沖突??紤]到窗口標(biāo)題一般是以文件名來命名的,因此可以使用Windows系統(tǒng)不允許包含在文件名中的字符作為參數(shù)的分隔符,如此即可解決窗口標(biāo)題和命令參數(shù)之間的沖突問題。所以本系統(tǒng)采用了“|”作為參數(shù)的分隔符。
對客戶端群發(fā)送指令,前文已闡述,采用UDP廣播的方式,但是在特殊的情況下則不能使用廣播傳輸。例如對某一臺或幾臺客戶機進行控制。此時可以采用單播或組播的方式。實際使用中,筆者發(fā)現(xiàn),有些系統(tǒng)瞬時承受能力有限,例如當(dāng)50個用戶同時登錄時,會出現(xiàn)擁塞現(xiàn)象,導(dǎo)致部分用戶出錯,需要重新登錄。此時只能讓各客戶端分批登錄,而每批的數(shù)量設(shè)置多少合適,又取決于網(wǎng)絡(luò)帶寬、服務(wù)器的配置等因數(shù),在實際操作中不好把握。為次,筆者采用UDP單播方式,向受控端間隔發(fā)送命令的方法來解決。也就是每次以單播方式向一個客戶端發(fā)送指令,然后暫停若干時間,再向下一個客戶端發(fā)送指令,其暫停時長可以由用戶自行設(shè)定。這樣就可以很好地解決系統(tǒng)瞬時承受能力的問題,同時也不會增加操作員額外的工作量。另外利用單播傳輸還實現(xiàn)了分組控制的功能,只需任意選擇若干臺客戶機,然后使用單播方式發(fā)送,即可實現(xiàn)分組控制的效果,操作方便簡單。
發(fā)送指令的核心代碼如下所示。
if isBroadcast then //廣播方式發(fā)送
SendString(UDPClient, '255.255.255.255',Port, Cmd)
else //單播方式發(fā)送
for I := 1 to HostList.Items.Count do
begin
SendString(UDPClient, HostList.Items[I - 1],Port, Cmd);
if isInterval then //間隔發(fā)送
Sleep(cnInterval); //暫停若干時間
end;
系統(tǒng)首先判斷是否為廣播方式,若是,則調(diào)用SendString函數(shù)向客戶端群發(fā)送指令,其中參數(shù)255.255.255.255為廣播地址,Cmd為命令字符串;否則,采用單播方式,此時循環(huán)調(diào)用SendString函數(shù)向選定的客戶端逐個發(fā)送指令,其中 HostList.Items[I - 1]參數(shù)為所選定的客戶端的IP地址。另外,如果是間隔發(fā)送,則發(fā)送一條指令后調(diào)用 Sleep函數(shù)暫停若干時間。
由于管理端給種子機發(fā)送截屏指令后,需要等待種子機返回數(shù)據(jù),而且此過程是不斷重復(fù)的,另外種子機返回的屏幕截圖數(shù)據(jù)比較大,往往需要分塊發(fā)送,因此本系統(tǒng)采用TCP作為其傳輸協(xié)議。一旦連接創(chuàng)建后就可以持續(xù)的收發(fā)數(shù)據(jù),而且TCP協(xié)議提供了流量控制、差錯控制和擁塞控制,保證了數(shù)據(jù)的可靠傳輸,極大地降低了系統(tǒng)開發(fā)的復(fù)雜度。
系統(tǒng)流程為,建立TCP連接后,管理端向種子機發(fā)送截屏指令,然后等待種子機返回屏幕畫面數(shù)據(jù),接收到數(shù)據(jù)后顯示客戶端屏幕畫面,然后再次發(fā)送截屏命令,如此重復(fù),截至系統(tǒng)關(guān)閉客戶端屏幕窗口為止。其核心代碼如下所示。
while repeatNow do
begin
try
//發(fā)送截屏指令
IdTCPClient.WriteLn(cnPIC);
//讀取客戶端返回的數(shù)據(jù)
IdTCPClient.ReadStream(ScreenStream);
//解壓流數(shù)據(jù)
UnCompressionStream(ScreenStream);
//顯示客戶端屏幕
ShowImage;
//響應(yīng)外界事件
Application.ProcessMessages;except
//出錯時顯示錯誤信息并退出循環(huán)
ON E:Exception do
begin
ShowErrorMessage(E.Message);
repeatNow := False;
end;
end;
end;
這里截屏指令不需要附帶任何參數(shù),因此直接發(fā)送截屏指令即可。如前所述,由于TCP協(xié)議已經(jīng)提供了流量控制、差錯控制和擁塞控制,因此管理端通過ReadStream函數(shù)直接讀取流數(shù)據(jù),即可獲得客戶端返回的截屏數(shù)據(jù)。
另外,為了減少傳輸?shù)臄?shù)據(jù)量,系統(tǒng)采用了數(shù)據(jù)壓縮技術(shù)[11],因此管理端收到的是經(jīng)過壓縮的數(shù)據(jù)流,所以此處先調(diào)用 UnCompressionStream函數(shù)解壓數(shù)據(jù)流,然后再顯示屏幕畫面。
對于客戶端,當(dāng)收到截屏指令后,首先獲取Windows桌面圖像,然后對數(shù)據(jù)流進行壓縮,接著把數(shù)據(jù)傳送給管理端。其核心代碼如下所示。
if Command = cnPIC then
begin
BmpStream.Clear;
//獲取Windows桌面圖像
CaptureScreen(0, 0, Screen.Width, Screen.Height);
//壓縮數(shù)據(jù)流
CompressionStream(BmpStream);
AThread.Connection.OpenWriteBuffer;
//發(fā)送數(shù)據(jù)
AThread.Connection.WriteStream(BmpStream,True, True, BmpStream.Size);
AThread.Connection.CloseWriteBuffer;
end
其中方法 CaptureScreen是獲取 Windows桌面圖像,其主要過程是通過調(diào)用Windows的API函數(shù)GetDC獲取Windows桌面句柄,然后復(fù)制其畫布。CaptureScreen方法的核心代碼如下所示。
Bitmap := TBitmap.Create;
//設(shè)置像素格式
Bitmap.PixelFormat := PixelFormat;
JPG := TJPEGImage.Create;
JPG.PixelFormat := jf8Bit;
//設(shè)置壓縮比
JPG.CompressionQuality := CompressionQuality;
JPG.Compress;
Desk := TCanvas.Create;
//獲取Windows屏幕句柄
Desk.Handle := GetDC(hwnd_desktop);
with Bitmap do
begin
Width := Screen.Width;
Height := Screen.Height;
//拷貝畫布
Canvas.CopyRect(Canvas.cliprect, Desk, Desk.cliprect);
end;
//保存為JPG格式
JPG.Assign(Bitmap);
//寫入到數(shù)據(jù)流
JPG.SaveToStream(BmpStream);
BmpStream.Position := 0;
為了進一步減少圖像的數(shù)據(jù)量而又不至于較大地降低圖像的質(zhì)量[12],系統(tǒng)使用了 JPEG格式來存儲截屏畫面,同時還允許用戶動態(tài)調(diào)節(jié)圖像的像素格式和壓縮比,以達到用較少的數(shù)據(jù)量傳輸較高圖像質(zhì)量的目的。
為了防止因窗口位置和大小不相同而導(dǎo)致鼠標(biāo)點擊時的位置錯誤,可以在需要時先同步窗口的位置和大小。
管理端先向種子機發(fā)送獲取窗口狀態(tài)命令,其核心代碼為:
SendCommand(ClientIP, Port, cnWIN)
其中ClientIP為種子機的IP地址,cnWIN為命令字符。
當(dāng)種子機收到命令后即開始獲取當(dāng)前活動窗口的標(biāo)題、位置和大小等信息,然后返回給管理端。獲取窗口狀態(tài)主要是通過Windows API函數(shù)獲取當(dāng)前活動窗口的句柄,然后再調(diào)用相應(yīng)的函數(shù)獲取窗口的位置、大小和標(biāo)題等信息,其核心代碼如下所示:
Hnd := GetForegroundWindow; //獲取當(dāng)前活動窗口句柄
if Hnd <> null then
begin
//獲取窗口區(qū)域
GetWindowRect(Hnd, Rec);
WX := Rec.Left;
WY := Rec.Top;
WW := Rec.Right - Rec.Left;
WH := Rec.Bottom - Rec.Top;
GetMem(Buffer, MaxBuf);
//獲取窗口標(biāo)題
if GetWindowText(Hnd, Buffer, MaxBuf) <> 0 then
WCaption := Buffer
else
WCaption := '';
FreeMem(Buffer);
end;
管理端收到種子機返回的窗口狀態(tài)信息后,即向其他客戶機發(fā)送窗口同步指令。
其他客戶機收到該指令后首先通過窗口標(biāo)題查找需要同步的窗口,然后設(shè)置其位置和大小,其核心代碼如下所示:
Hnd := FindWindow(nil, PCHAR(pCaption)); //根據(jù)標(biāo)題查找窗口
if (Hnd <> 0) then begin
//設(shè)置為活動窗口
SetActiveWindow(Hnd);
BringWindowToTop(Hnd);
ShowWindow(Hnd, SW_SHOWNA);
SetForegroundWindow(Hnd);
//設(shè)置位置和大小
SetWindowPos(Hnd, HWND_TOP, pX, pY,pW, pH, SWP_SHOWWINDOW);
end;
鼠標(biāo)的操作包括位置移動、按鍵的按下和按鍵的彈起,它們分別通過管理端控制屏幕上的 On-MouseMove、OnMouseDown和OnMouseUp事件來捕獲這些信息。
位置的移動。當(dāng)鼠標(biāo)在控制屏幕上移動時,管理端隨即把鼠標(biāo)的位置信息發(fā)送給客戶端;客戶端收到指令后,通過 SetCursorPos函數(shù)設(shè)置鼠標(biāo)的位置。
鼠標(biāo)按鍵按下。當(dāng)鼠標(biāo)按鍵按下后,管理端首先檢查是左鍵還是右鍵被按下,然后把按鍵信息發(fā)送給客戶端;客戶端收到指令后,通過Mouse_event函數(shù)模擬鼠標(biāo)的相應(yīng)按鍵按下。
鼠標(biāo)按鍵彈起。當(dāng)鼠標(biāo)按鍵彈起后,管理端同樣先檢查彈起的是左鍵還是右鍵,然后把該信息發(fā)送給客戶端;客戶端收到指令后,通過Mouse_event函數(shù)模擬相應(yīng)的鼠標(biāo)按鍵的彈起。
鍵盤的操作包括按鍵的按下和按鍵的彈起,它們分別通過管理端控制窗口上的 OnKeyDown和OnKeyUp事件來捕獲。
在控制窗口上,當(dāng)按下鍵盤的某個按鍵后,管理端首先獲取被按鍵的鍵值,然后把鍵值信息發(fā)送給客戶端;客戶端收到后,通過函數(shù) keybd_event模擬鍵盤按下相應(yīng)的按鍵。
在控制窗口上,當(dāng)鍵盤的某個鍵彈起后,管理端首先獲取所彈起鍵的鍵值,然后把該信息發(fā)送給客戶端;客戶端收到后,通過keybd_event函數(shù)模擬該按鍵彈起。
對于組合按鍵的捕獲,由于 OnKeyDown和OnKeyUp事件除了能捕獲可見字符按鍵之外,功能鍵,如Ctrl、Shift等,同樣能捕獲。例如管理端執(zhí)行Ctrl+A的鍵盤操作,其過程是先按下Ctrl鍵,然后再按下A鍵,接著彈起A鍵,最后彈起Ctrl鍵,因此管理端只需按捕獲的順序?qū)⑾鄳?yīng)的信息發(fā)送給客戶端即可,無需額外的操作。
有時候在進行集中控制時,需要客戶端各自輸入不同的信息,例如在進行考試系統(tǒng)的測試時,需要輸入不同的賬號。經(jīng)過分析,這些數(shù)據(jù)往往是按順序排列,都是有規(guī)律的。例如下面的賬號:AZ1844001,AZ1844002,…,AZ1844090,前面AZ1844是相同的,后面三位為順序號。此時可以先統(tǒng)一輸入前面相同的部分,然后由客戶端自動輸入后面的順序號。而順序號可以由IPv4地址的第四段加上偏移量來計算獲得。
由于實驗室的計算機其IP地址不一定都從1開始分配,而且所需輸入的順序號也不一定都從1開始,因此就要通過偏移量來進行控制。例如,IP地址從192.168.1.100開始分配,而所需輸入的順序號從51開始,則偏移量為51-100=-49,經(jīng)計算,該客戶端的順序號為100+(-49)=51,符合要求。
另外,自動輸入時還需要規(guī)定字符的長度,如上例,則要規(guī)定長度為 3,位數(shù)不夠時通過在前面補0來填充。
客戶端在自動輸入時,是通過keybd_event函數(shù)模擬某個按鍵被按下接著再彈起來實現(xiàn)的。
本系統(tǒng)通過使用集中控制技術(shù),實現(xiàn)了在一臺管理機上,對同一子網(wǎng)內(nèi)的所有客戶機進行集中、統(tǒng)一、同步地遠程控制,而利用單播和時延技術(shù),解決了某些系統(tǒng)瞬時承受能力有限的問題,同時系統(tǒng)還實現(xiàn)了在不同的客戶端自動輸入不同字符串的功能。該系統(tǒng)的使用,極大地減少了管理員對計算機實驗室在進行軟件部署和考前測試等日常維護和管理當(dāng)中的工作量,有效地提高了工作效率。
目前該系統(tǒng)已開發(fā)完成,并已取得國家計算機軟件著作權(quán),在筆者所在單位的各計算機實驗室得到了持續(xù)而廣泛的應(yīng)用,為計算機實驗室的維護工作發(fā)揮了重要的作用。
[1] 趙康, 李康, 孟晨宇, 初敬敬, 康曉鳳. 基于C/S架構(gòu)的遠程協(xié)助和管理系統(tǒng)[J]. 軟件, 2015, 36(4): 14-17.
[2] 陳劍偉, 李志芳. 混合模式校園機房在線管理系統(tǒng)的設(shè)計與實現(xiàn)[J]. 軟件, 2017, 38(6): 70-74.
[3] 朱永強, 湯雄. 基于VNC的遠程桌面?zhèn)鬏攨f(xié)議分析與研究[J]. 計算機系統(tǒng)應(yīng)用, 2016, 25(11): 284-287.
[4] 陸萬青. 虛擬化云桌面在高校計算機實驗室中的應(yīng)用研究[J]. 軟件, 2016, 37(12): 230-232.
[5] 宋金城. Hyper-V虛擬環(huán)境下高職院校計算機實驗室網(wǎng)絡(luò)設(shè)計研究[J]. 軟件, 2014, 35(11): 124-125.
[6] 易俗. 基于桌面云的高校計算機實驗室管理研究[J]. 遼寧大學(xué)學(xué)報(自然科學(xué)版), 2016, 43(3): 277-280.
[7] 許葵元. 計算機網(wǎng)絡(luò)遠程控制系統(tǒng)的應(yīng)用研究[J]. 現(xiàn)代工業(yè)經(jīng)濟和信息化, 2015, 5(24): 106-107.
[8] 何少宜. 高校計算機實驗室管理與維護探究[J]. 無線互聯(lián)科技, 2017(22): 133-134.
[9] 萬玉鑄, 徐志江, 盧為黨, 華驚宇. 具有高吞吐量的可靠UDP協(xié)議[J]. 計算機工程與設(shè)計, 2017, 38(12): 3202-3206+3212.
[10] 郭峰. 計算機通信傳輸控制技術(shù)研究[J]. 信息與電腦(理論版), 2017(9): 147-148.
[11] 田浩, 孫劍偉. 基于衛(wèi)星數(shù)據(jù)縮減的傳輸優(yōu)化技術(shù)研究與實現(xiàn)[J]. 軟件, 2017, 38(2): 98-104.
[12] 李素鈞, 廖勝, 李強. 基于多核DSP的H. 264圖像壓縮編碼的并行化實現(xiàn)[J]. 電子設(shè)計工程, 2017, 25(4): 126-129.