guacamole整体架构
一、??? 架構
guacamole架構分為三個部分,分別是guacamoleclient、guacamole server、guacamole proxy。
guacamole client由JavaScript實現,一旦它被加載到用戶的web瀏覽器里,它立即連接到guacamoleserver。這二者之間的交互是通過HTTP之上的guacamole 協議完成的。
guacamole server由Java實現,作為web應用部署。它讀取guacamole協議的數據,并將之轉發到guacd(guacamoleproxy)。
guacamole proxy是原生應用,由C實現,它將guacamole協議的數據翻譯成RDP、VNC等協議的數據,并以客戶端的身份連接到多個遠程桌面服務端。
協議間的翻譯由guacd(guacamoleproxy)完成。guacamole server和guacamole client僅僅知道guacamole協議,無需知道使用的是那個具體的遠程桌面協議。
guacamole是一個中心化的網關,通過它可以訪問多個遠程桌面服務端(支持多種遠程桌面協議)。它有可擴展的架構,編譯定制化開發,還提供了一套基于HTML5進行遠程訪問的通用API。
1、???協議(guacamole)
guacamole協議是一個遠程屏幕繪制和事件傳輸協議。擁有這兩項能力的協議自然而然與遠程桌面協議有相同的功能。guacamole協議與遠程桌面協議的設計原則不同,guacamole協議本身不實現任何特定桌面系統的遠程桌面功能。
guacamole協議是其他現有遠程桌面協議的超集。guacamole要支持一個具體的遠程桌面協議(比如RDP),只需要實現一個中間層來做兩種協議之間的翻譯,這與實現一個原生客戶端是一樣的,只是原生客戶端在本地繪制屏幕,這個中間層卻將屏幕繪制到遠端屏幕。
guacd(guacamoleproxy)就是這個中間層。
2、???遠程桌面插件管理模塊(guacd)
guacd是guacamole的核心,guacd通過從web應用接收到的指令,動態地加載客戶端插件,通過客戶端插件連接到具體的遠程桌面服務端。
guacd伴隨guacamole一起安裝,以守護進程的形式在后臺運行,監聽來自web應用的TCP連接。它本身僅僅支持guacamole協議,它并不支持任何具體的遠程桌面協議(比如RDP),它通過加載的客戶端插件來實現對具體的遠程桌面協議的支持。客戶端插件被加載后,就獨立運行。客戶端插件對自身和web應用之間的交互有完全的自主控制能力,知道客戶端插件終止運行。
guacd與客戶端插件都基于libguac庫開發,這個庫提供了對guacamole協議更方便和更抽象的使用方法。
3、???連接及用戶管理模塊(web application)
它是guacamole系統中,直接與用戶交互的部分。
它本身不支持任何其他的遠程桌面協議,它依賴于guacd,它本身僅僅作為一個web接口以及權限管理層而存在。
?
二、??? 協議(guacamole)
1、???協議格式
guacamole的協議由指令組成。指令與指令之間用分號分隔,指令內部是由逗號分隔的列表。每個指令內部的第一個元素是指令的操作碼,指令內部所有后續的元素都是這個指令的參數。(注:這里都應該是英文的逗號,分號,下同)
?
操作碼,參數1,參數2,參數3,…;
?
指令內部的列表里的每個元素,都有一個十進制的正整數前綴,這個前綴與元素的值通過英文的句號分隔。這個前綴指明表示元素的值的unicode字符的個數,元素是按UTF-8編碼的。
?
長度.值
?
服務器發往客戶端,或者客戶端發往服務器的消息,由任意數量的完整指令組成。客戶端發往服務端的消息多數是控制指令(用于建立連接、斷開連接)和事件指令(鼠標事件、鍵盤事件)。服務端發往客戶端的消息多數是繪制指令(緩存、裁切、繪圖),服務端講客戶端看作遠端的屏幕。
?
例如,一個完整有效的用于設置屏幕大小為1024x768的指令如下:
?
4.size,1.0,4.1024,3.768;
?
上述指令將被解碼為四個元素:“size”,操作碼(也可以叫指令編號,用于區別不同的指令),表示這個指令用于設置屏幕大小。“0”,默認的圖層序號(繪制圖像的時候有多個圖層,這里大概是說第0層,也就是最外層)。“1024”,期望的屏幕寬度,以像素點為單位(就是說期望寬為1024個像素點)。“768”,期望的屏幕高度,以像素點為單位。
?
guacamole的協議格式這樣設計是很必要的,因為這樣設計使其能以流的形式被傳輸,而且易于被JavaScript解析。JavaScript確實原生支持類似于XML、JSON這類格式的消息,但是這類格式的消息都不能以流的形式傳輸。JavaScript在解析這類格式的消息前必須接收到完整的XML或者JSON的包。而guacamole協議的消息,卻可以一邊接收一邊解析。它的指令內每個元素的長度前綴使得解析器不用遍歷每個字符就可以完成指令(元素)之間的跳轉。
2、???協議握手過程
?
握手的過程是guacamole協議建立連接的過程。以一個“select”指令開始,這個指令從客戶端發往服務器端,并告訴服務器加載哪個協議。
?
6.select,3.vnc;
?
服務器接收到“select”指令后,會加載對于的客戶端組件,并且回復一個“args”指令,這個指令指明了服務器端需要的參數名列表。
?
4.args,8.hostname,4.port,8.password,13.swap-red-blue,9.read-only;
?
客戶端接收到服務端可接受的參數名列表后,需要回復給服務器,自己支持的audio、video、image的mimetype,最佳的屏幕尺寸以及分辨率,以及所有的服務器要求的參數的值,即使是空,也要回復。任意一個要求沒被滿足,連接都將被關閉。客戶端回復給服務端的消息如下。
?
4.size,4.1024,3.768,2.96;
5.audio,9.audio/ogg;
5.video;
5.image,9.image/png,10.image/jpeg;
7.connect,9.localhost,4.5900,0.,0.,0.;(這里就是上一條服務器消息里,服務器要求的參數,客戶端把值填上,沒有值的,留空白,長度前綴為0,回復給服務器端)
?
為了表示的易讀性,我們將每個指令放在單獨的一行,但是在真實的協議中,是不換行的,就是說,指令與指令之間沒有換行符。事實上,如果一個指令后接的不是一個新指令的開始,連接將被關閉。
?
這個例子中,客戶端表明了,最佳屏幕尺寸是1024x768。DPI為96DPI。它支持OggVorbis(一種音頻壓縮格式)的音頻(audio),但是不支持視頻(video),可以接受PNG、JPEG格式的圖片。客戶端想連接到localhost的5900端口。余下的三個參數留空。
?
一旦客戶端把這些指令發到了服務器端。服務器端就會嘗試以接收到的參數初始化連接(這里初始化的連接應該是guacamole到最終的vnc server或者rdp server的連接),如果連接建立成功,則回復給客戶端一個“ready”指令。這個指令包含了新的客戶端連接的ID(這里是客戶端到服務器端的ID,還是服務器端到vnc server、rdp server的連接的ID,尚不清楚),也標志著交互階段的開始。這個ID是一個任意的字符串,但是在所有已激活的連接中是唯一的。
?
5.ready,37.$260d01da-779b-4ee9-afc1-c16bae885cc7;
?
“ready”指令一發送,真正的交互階段就開始了。繪制和事件指令在客戶端和服務器端傳輸直到連接關閉。
?
3、???協議整合
guacamole協議可以嵌套傳送自身。這樣大尺寸的指令或者單獨的流上的多條指令可以通過同一個流來發送,而且不會互相阻塞。
?
一個“nest”指令只有兩個參數:一個參數是一個任意的整數作為流編號,表明這個數據屬于哪個流。另一個參數是指令數據本身。這個流編號用于確定如何在接收到指令數據后重組指令,所以流編號參數很重要。客戶端接收到“nest”指令后,流編號相同的,將被客戶端按接收的順序重組為完整的指令,重組一旦完成,指令將會立即被執行。
?
上述機制很重要,尤其是當數據需要以流的形式而不是單個原子指令的形式發送到客戶端的時候。
4、???繪制
上圖表示了圖層運算的概念,包括clear、over、in、out、atop、xor。
?
合成
guacamole協議通過“通道掩碼”提供了合成操作。術語“通道掩碼”描述了一種機制,這種機制是通過四種不同的圖像數據源來列舉所有可能的合成操作。
將這種機制設計在guacamole協議中用于實現所有的圖像合成操作。四種不同的圖像數據源分別是:源圖層在目標圖層的不透明區,源圖層在目標圖層的透明區,目標圖層在源圖層的不透明區,目標圖層在源圖層的透明區。對每個“通道”指定一個二進制的值,就會為每種可能的操作創建一個唯一的整數ID。這些操作與Porter和Duff的論文里的操作相似。HTML5里的canvas標簽也使用了Porter/Duff方式來描述它的圖像合成操作(與其他的圖像API一樣)。guacamole協議支持的圖像合成操作與瀏覽器已經普遍支持的圖像操作一致(尚有少許不支持)。下列合成操作已經被實現,且能夠正確地在瀏覽器里運行。
????? B out A(0x02)
???????????? 清除目標圖層中源圖層不透明的部分,而且不會繪制任何東西。可用于遮蓋。
????? A atop B(0x06)
???????????? 在目標圖層中填充源圖層中不透明的部分。
????? A xor B(0x0A)
???????????? 與邏輯上的xor操作一樣。但是這是圖像合成操作,不是位運算,實質含義是在目標圖層的透明部分繪制源圖層,在源圖層的透明部分繪制目標圖層。
????? B over A(0x0B)
???????????? 與你期望的常規繪制相反。源圖層出現在目標圖層透明的地方。如同你將目標圖層繪制在源圖層上,而不是反過來。
????? A over B(0x0E)
???????????? 最常見的合成操作,在目標圖層繪制全部的源圖層,除了源圖層透明的地方。
????? A + B(0x0F)
???????????? 將源圖層與目標圖層相加起來,并將結果填充到空白的畫布上。
?
下列操作已經實現,但是可能不能保證在webkit內核的瀏覽器里正確地執行。這些瀏覽器總會在源圖層的透明部分包含目標圖層。
?
B in A (0x01)
???????????? 在源圖層不透明的地方繪制目標圖層,清空所有的源圖層透明以及目標圖層透明的地方。
A in B (0x04)
在目標圖層不透明的地方繪制源圖層,清空所有的源圖層透明以及目標圖層透明的地方。
A out B (0x08)
在目標圖層透明的地方畫源圖層,清空所有的源圖層不透明以及目標圖層不透明的地方。
?
B atop A (0x09)
????? 在源圖層不透明的地方填充目標圖層。
?
A (0x0C)
????? 填充源圖層,忽略目標圖層。
?
下列操作已經定義,但是尚未實現,且在HTML5的canvas里也不存在這些操作。
?
????? CLear(0x00)
???????????? 在目標圖層中清空所有已經存在的圖像數據。
????? B (0x03)
???????????? 什么也不做。
????? A xnor B(0x05)
???????????? 將目標圖層與源圖層不透明的地方相加起來。清空所有目標圖層與源圖層透明的地方。這與A+B相似,除了透明的地方要清空以外。
????? (A+B)atop B(0x07)
???????????? 在目標圖層不透明的地方繪制源圖層,并保留目標圖層余下的地方。
????? (A+B)atop A(0x0D)
???????????? 在源圖層不透明的地方繪制目標圖層,并且復制源圖層余下的地方。
?
圖像數據
????? guacamole協議與其他遠程桌面協議一樣,提供了一種方法來發送任意的矩形圖像數據,并且把它放入緩存或者屏幕上可見的矩形部分。guacamole協議通過“img”指令建立一個流,用于以PNG,JPEG或者WebP的格式傳送的原始圖像數據。根據使用的格式的不同,通過這種方式傳送的圖像更新數據可能以RGB或者RGBA(A代表透明度)編碼,如果通過libguac傳送的話,還會被自動調色。guacamole里以流的方式傳輸圖像的機制,也被用于傳輸其他類型的數據,比如音頻或者文件。關于guacamole協議里流的更多細節,參考“流與對象”章節。
?
圖像數據可以被發送到任意指定的矩形,包括圖層或者緩存。將圖像數據發送到圖層意味著立刻可見,講圖像數據發送到緩存意味著可以在將來被重用。
?
在圖層之間拷貝圖像數據
?
圖像數據可以在圖層或者緩存之間拷貝,這在屏幕滾動的時候很有用(屏幕滾動的時候,更新的圖像經常與之前的圖像完全一樣),在緩存某個部分的圖像的時候,也很有用。
?
VNC和RDP都支持拷貝屏幕某個區域的圖像數據,并將之放置到這個屏幕內其他區域去。RDP還提供了額外的將圖像拷貝到緩存和從緩存中提取圖像放到屏幕的支持。guacamole吸收了這些概念,并將之進一步發展,將屏幕可見(圖層)與屏幕不可見(緩存)的存儲統一起來。guacamole的“copy”指令使你可以拷貝一個矩形的圖像數據,并且可以將其放置到其他圖層。無論這個圖層是源圖層還是其他的屏幕可見圖層,亦或是一個屏幕不可見的緩存。
?
圖像原語
?
guacamole協議提供的基本圖像操作,與Cario或者HTML5的canvas標簽提供的圖像操作類似。在許多情況下,這些圖像操作原語有助于遠程繪制,而且傳送圖像操作原語比直接傳送相應PNG圖像消耗的帶寬小得多,所以也是更可取的方式。但是需要注意的是,過度使用原語會導致客戶端的處理負擔增加,這可能會導致客戶端的性能降低,尤其是客戶端的計算能力有限的情況下,比如客戶端是手機或者平板。
?
緩存和圖層。
?
guacamole里的每個繪制操作都會作用到一個具體的圖層,每個圖層都有一個唯一的編號來標識它自身。當這個編號是負數的時候,這個圖層是不可見的,可以用于存儲或者緩存圖像數據。此時,圖層通過編碼被引用,且等同于文檔中所謂的“緩存”,當通過某個指令引用圖層的時候,圖層會被自動創建。
?
有一個圖層會被當作默認圖層。這個圖層的編號為0,調整這個圖層大小的時候就會調整整個遠端屏幕大小。其他圖層創建時候的初始大小與默認圖層的大小一致。緩存的初始大小為0x0,并且會自動調整大小來適配裝入的內容。
?
非緩存圖層可以在其他圖層中被移動或者嵌套。通過這種方式,提供了一種簡單的硬件加速合成圖像的方式。如果你需要一個窗口浮現在另外的窗口之上,或者你想要移除一些對象,又或者你想要自動保存一些對象之下的圖像數據,圖層是實現這些需求較好的方式。如果一個圖層嵌套在其他圖層里,它的位置是相對于父圖層的。當父圖層被移動或者重排序(調整圖層之間的順序)的時候,子圖層會隨之移動以及重排序。如果子圖層超出了父圖層的邊界,字圖層將被裁切。
?
5、???流與對象
guacamole支持傳輸剪切板內容,音頻內容,視頻內容和圖像數據,以及文件和任意的命名管道。
?
特殊語義的指令將會通過新分配的流傳送。例如,用于播放媒體文件的“audio”或“video”指令。用于傳輸文件的“file”指令,用于在客戶端和服務端傳輸任意數據的“pipe”指令。在某些情況下,將通過已命名的流傳送的結構化集合對象的方式來顯示指明流的能力范圍和語義。
?
流一旦被創建,將通過“blob”指令一塊一塊地傳送數據,通過“ack”來確認已收到的消息,流的結束通過一個“end”指令來標識。
?
6、???事件
當任意一端有改變時,比如鍵盤上的鍵被按下,鼠標被移動,剪切板的數據發生了改變,一個描述事件的指令將被發送。
7、???斷開連接
服務端和客戶端都可以在任意的時刻斷開連接。沒有要求在斷開連接之前客戶端和服務端要協商一下。任意一端想要斷開連接,并且原因已知,它們就可以用“disconnect”或者“error”指令來斷開連接。
?
斷開連接的時候,“disconnect”指令應當由客戶端發送,這很大程度上是出于禮貌,因為“disconnect”指令或許不是總能被及時發送。(這里不明白原文意思)
?
如果客戶端發生了錯誤,或者服務端檢測到客戶端插件的出了問題,服務端發送一個“error”指令,在參數中描述錯誤原因,以此通知客戶端連接已經關閉。
?
三、??? 遠程桌面插件管理模塊(libguac)
libguac是一個C語言的API,用于擴展或者二次開發guacamole。guacamole所有的本地組件都是基于libguac開發的。這個庫提供了基礎功能用于擴展本地組件的本地功能(通過實現客戶端插件的方式)。
?
libguac主要用于開發客戶端插件,比如libguac-client-vnc或者libguac-client-rdp,或者用于開發一個支持guacamole協議的代理,例如guacd。這一章節主要介紹如何使用libguac,以及如何使用它以guacamole協議與協議的對端溝通。
?
1、???錯誤處理
libguac里大多數的函數通過返回一個零或者非零值的方式來處理錯誤,由當前函數自己選擇合適的值。如果發生錯誤,guac_error變量將被設置為一個對應的值,同時guac_error_message 包含一個靜態分配的易于人類閱讀的字符串用于描述錯誤的內容。這些變量刻意模仿errno和errno.h里提供的功能。
?
guac_error和guac_error_message都是在error.h里定義的。可以通過guac_status_string()方法將guac_error表示的錯誤信息恢復成一個易于人類閱讀的字符串,這個字符串也是靜態分配的。
?
如果客戶端插件里的函數在發生錯誤的時候適當地設置了guac_error和guac_error_message,并通過guacd將這些信息寫到系統日志中,將更有助于最終用戶和開發者。
2、???客戶端插件
上圖表示libguac在guacd中的位置,以及客戶端插件與guacd之間的關系。
客戶端插件是一個通過libdl函數動態加載的庫。每個客戶端插件都要遵守如下的命名約定,庫的名稱應當叫做libguac-client-協議。如果不遵守這個約定,guacd在加載客戶端插件的時候,將不能找到對應的庫(也就是客戶端插件)。
?
當加載客戶端插件的時候,guacd以想要加載的客戶端插件對應的協議名稱來調用guac_client_plugin_open()方法。該方法成功執行后,將以guac_client_plugin實例的形式返回一個句柄給包含客戶端插件的庫。該實例最終將在guacd結束使用它的時候被guac_client_plugin_close()回收。這些方法既提供給guacd使用,也可以提供給其他的代理實現使用,即使這代理實現駐留在其他客戶端插件內(不是很明白原文意思)。
?
一旦客戶端插件加載成功,guacd調用guac_client_plugin_init_client()以初始化客戶端,這個方法調用在客戶端內部調用guac_client_init(),因而所有的客戶端插件內都必須定義該方法(guac_client_init())。這個方法是所有的客戶端插件的入口方法,類似于C語言程序中的main()方法。
?
當guacd按照guacamole協議進行握手操作的時候,它會去讀取一個靜態分配的,以NULL為截斷標志的參數名集合變量,這個變量在客戶端插件里聲明為GUAC_CLIENT_ARGS。就像guac_client_init()一樣,所有的客戶端插件如果想要正常工作都必須定義這個變量。握手過程結束后,guacd將會初始化并且填充guac_client數據結構,以及這個數據結構里包含的guac_client_info結構,連同從當前連接的客戶端收到的參數數量、參數值一起傳送給guac_client_init()方法。
?
客戶端插件需要向guac_client數據結構里填充適當的事件處理函數,一旦這個動作完成,guacd_client_init()函數將成功返回,與客戶端的溝通將正式開始,guacd將在需要的時候調用guac_client數據結構里事件處理函數來處理接收到的任意指令。
?
3、???圖層和緩存
處理繪制指令時,主要是操作圖層(layer)對象,在libguac中,以guac_layer數據結構來代表圖層對象。每個guac_layer都由guac_client_alloc_layer()或者guac_client_alloc_buffer()方法來分配。具體使用哪個取決于想要圖層還是緩存。圖層和緩存使用完后,通過guac_client_free_layer() 或者guac_client_free_buffer()方法來釋放分配的資源。
重要:
?
圖層和緩存在分配和釋放資源的時候,需要小心地按照類型(是圖層還是緩存)調用相應的方法。guac_client_free_layer()只能用于釋放guac_client_alloc_layer()方法分配的圖層。uac_client_free_buffer()只能用于釋放guac_client_alloc_buffer()方法分配的緩存。并且都必須在同一個guac_client實例上調用這些方法。
如果不遵守這些約束,調用這些方法的結果將不可預知。
?
在遠程客戶端上創建新的圖層是代價高昂的操作,復用已經存在的圖層將有助于節約客戶端資源,使用上述這些圖層管理方法,將使客戶端在圖層的初始使命完成后能夠復用圖層。
?
通過圖層(layer)和緩存(buffer),guacamole得以提供硬件加速合成圖像以及緩存更新(cached updates)。創造性地使用圖層和緩存可以高效地更新客戶端,這也意味著流暢的畫面以及更好的實時響應。
?
無論開發者是否分配了新的圖層或緩存,總會存在一個默認圖層,在libguac中以GUAC_DEFAULT_LAYER表示。如果期望僅在當前連接的遠程桌面的主屏幕上繪制,那么繪制指令將默認圖層作為操作對象即可。
?
4、???發送指令
guacamole里所有的繪制操作都是通過基于guacamole協議向已連接的客戶端發送指令的方式來實現的。音頻操作,視頻操作,文件操作都是一樣的。guacamole支持的所有功能最終都將映射到一個或多個指令上,這些指令都是guacamole協議的文檔的一部分。
?
libguac的繪制操作多是憑借Cairo的方法實現的,Cairo的方法在cairo_surface_t對象上進行繪制(參考CairoAPI文檔),繪制完成后,通過img指令以及隨后的blob指令以流的形式發送到客戶端,發送操作通過調研guac_client_stream_png()方法完成的。Cairo是libguac的依賴庫,它是一種成熟且穩定的圖像緩存繪制庫。繪制好的圖像最終以易于處理的PNG格式被發送到客戶端。
?
與Cairo API和HTML5 的canvas標簽提供的繪圖原語(就是直接的繪圖指令,比如畫一個圓,畫一個矩形之類的,而不是畫一個image)支持類似,guacamole協議也支持繪圖原語。相關的指令在guacamole協議文檔中有專門的一章來說明。這些指令與guacamole協議中其他指令一樣,在libguac中都提供了對應的方法,其命名符合約定:guac_protocol_send _OPCODE(),這里的OPCODE就是每個具體的指令名稱。
?
每個協議方法都需要一個guac_socket作為參數,這個參數是供libguac使用的帶緩沖區的I/O對象。與已連接的客戶端對象對應的guac_socket對象存儲在當前正在使用的guac_client對象的socket成員中,使用方法如下:
?
guac_protocol_send_size(client->socket,GUAC_DEFAULT_LAYER, 1024, 768);
?
5、???協議嵌套(分片?整合?聚合?)
有的時候單個指令的尺寸很大,尤其是與音頻視頻相關的指令,發送這類指令最好的方式就是將其拆分為小的獨立的包,并通過“nest”指令來發送這些包。這樣,大尺寸的指令就可以與小尺寸的指令間隔著發送,小尺寸的消息就不會被大尺寸的消息阻塞,從而保證了及時響應能力不會降低。由于先前的指令沒被解析前,后續的指令不會被解析,所以為了保持較好的交互實時性,應當特別注意不要發送尺寸過大的指令。
?
libguac提供了guac_socket_nest()方法來自動嵌套發送指令。這個方法會返回一個新的guac_socket,用于傳輸nest指令的數據,而不是直接在原來的socket上傳輸nest指令的數據。
?
注意
guacamole協議要求每個指令的尺寸是明確。如果需要實時傳輸音頻或視頻流,必須將其分割成一個個大小確定的數據塊,再傳輸(因為流本身沒有明確尺寸)。分隔后的單個塊,如果尺寸越小,越容易受網絡抖動的影響進而產生明顯的延遲。如果尺寸越大,越不容易受網絡狀況的影響,但是要求客戶端等待更長的時間才能開始使用數據(要等待接收完成)。
視頻或者音頻的數據包的尺寸與nest指令的尺寸是不相關的,即使較大尺寸的數據包也可以使用nest指令傳輸。而這正是nest指令的目的:將較大尺寸的數據包切分成較小尺寸的數據包再發送。
?
6、???事件處理
鍵盤事件:
當客戶端的鍵盤被按下或者被釋放的時候,客戶端就會發送一個鍵盤事件指令到服務端,guacd通過調用客戶端插件注冊在guac_client變量里的鍵盤事件處理函數來解析及處理鍵盤事件指令。傳遞給這個事件處理函數的參數包括正在改變狀態的鍵的鍵碼以及狀態(按下還是釋放)。
?
鼠標事件:
鼠標移動或者鍵被按下或者釋放的時候,客戶端發送鼠標事件指令到服務端。這些指令與鍵盤事件指令一樣,通過鼠標事件處理函數被解析和處理。鼠標事件處理函數也是客戶端插件注冊在guac_client變量中的。傳遞給鼠標事件的處理函數包括當前鼠標的X和Y坐標,以及一個掩碼來表示哪個鍵被按下哪個鍵被釋放。
GUAC_CLIENT_MOUSE_LEFT:鼠標左鍵被按下
GUAC_CLIENT_MOUSE_MIDDLE:鼠標中鍵被按下
GUAC_CLIENT_MOUSE_RIGHT:鼠標右鍵被按下.
GUAC_CLIENT_MOUSE_UP:鼠標滾輪向上滾動一格
GUAC_CLIENT_MOUSE_DOWN:鼠標滾輪向下滾動一格
?
剪切板事件:
當客戶端發送一個應當被傳輸到遠程桌面的剪切板的數據時,將觸發客戶端插件注冊在guac_client變量里的剪切板事件處理函數。傳輸的數據是以null作為終止符字符串,以UTF-8格式編碼。目前尚不支持其他格式的剪切板數據。
?
處理來自服務端的消息
guac_client變量中的handle_messages指向服務端消息處理函數。為每個服務端消息創建一個線程來處理它,這種方式看起來直觀,但是一定不能這樣做。因為guacd的一個重要任務是在自身和guacamole client之間傳輸同步(sync)指令,來判斷guacamole client現在的狀態,是在線還是離線。而且這個處理函數會限制服務端消息的頻率。如果忽略了這一點,guacamole client將會被同步指令淹沒,導致處理不過來,使用戶體驗不佳。
?
四、??? 連接及用戶管理模塊(guacamole-common)
這是一個Java API。它提供了一個基礎方法用于在guacamole client與guacd之間傳輸guacamole協議的數據。這個API的主要目的是方便二次開發,以加強其安全模型。
1、???HTTP隧道
本模塊通過GuacamoleHTTPTunnelServlet類來實現http隧道。這個servlet接收所有的來自js客戶端的請求,并翻譯為connect、read、write三種請求,并分別調用對應的處理方法:doConnect()、doRead()、doWrite();
使用這個API時,只需要繼承GuacamoleHTTPTunnelServlet類,并且實現自己的doConnect()方法。doConnect()里是一個很適合做授權的地方,這里授權失敗,將不會創建http隧道。
GuacamoleTunnel由GuacamoleSocket實現,后者是一個抽象接口用于訪問下層的到guacd的TCP socket連接。
2、???協議使用
該模塊提供了對guacamole協議的支持。這里實現了兩個類:GuacamoleReader和GuacamoleWriter,這兩個類與Java里的Reader和Writer的類類似,不過專用于guacamole協議的處理。
GuacamoleReader
這個類提供了基本的read()方法,以char數組的形式返回一個或多個完整指令。
GuacamoleWriter
這個類提供了基本的write()方法,用于寫入完整的指令(GuacamoleInstruction)。
五、??? 瀏覽器客戶端(guacamole-common-js)
1、???瀏覽器客戶端
·這是一個Java Script? API
·用途:
???? 用于開發guacamole客戶端
·提供:
???? ①客戶端的Java Script實現
②HTTP隧道:從JavaScript中獲取協議數據到guacd或web應用程序的服務器端
③鼠標、觸摸、鍵盤的抽象對象
④可擴展的虛擬鍵盤
·優點:
???? ①已經實現了guacamole協議的絕大部分指令
???? ②大部分指令由客戶端自動處理,
? 需自己處理:name(用于命名連接)、clipboard(用于在客戶端更新剪貼板數據)、error(當服務器端出錯時使用)
·使用方法:
①實例化
②手動添加客戶端
③Connect(),傳數據
?
2、???HTTP 隧道
①Java script端請求,Java端處理
②通過將相對URL提供給服務器端隧道servlet來創建隧道
? var tunnel = new Guacamole.Tunnel(“tunnel”);
3、???輸入抽象
·鼠標:
對象:guacamole.mouse
實例化:mouse.state
事件:onmousedown、onmousemove、onmouseup
?
·鍵盤:
對象:guacamole.keyboard
事件:keyup、keydown
處理方法:K11? keysym?用來表示具體哪個鍵被按下
?
4、???觸摸屏事件(todo)
//todo
已經部分實現了觸摸事件向鼠標事件的模擬(down、up、move),包括移動和點擊鼠標(絕對定位模式和相對定位模式),未實現觸摸的滑動操作(與鼠標滾輪事件的區別,滑動有任意方向,滾輪只有前后兩個方向。)
對象:guacamole.touchpad/ guacamole.touchscreen
實例化:mouse.state
5、???虛擬鍵盤
·鍵盤布局
??? Layout XML :
? <key>:單純一個標簽
? <cap>:若干個,用來描述對應哪個X11 keysym
? <row>:行
? <column>:列
·鍵盤顯示
①添加一個鍵盤
②設置像素,鍵盤的寬與高
·設計樣式
有幾個CSS類,可用來自行調整
例如:guac-keyboard、guac-keyboard-gap、guac-keyboard-cap等
·事件的處理
與實體鍵盤生成的event完全相同
只含有keyup、keydown
因為都只包含X11 keysym
?
6、???屏幕尺寸自適應(todo)
????? //todo
7、???GPS(todo)
?
8、???多媒體外設(todo)
攝像頭
聲卡
?
9、???文件訪問外設(todo)
usb
?
六、??? 自定義認證和授權
1、???授權模型
Web應用程序通過收集可用的所有憑據并將它們傳遞到類“authentication providers”來處理此身份驗證。 發送完數據,返回上指定對象,該對象提供對其他用戶和連接(如果有的話)的受限訪問。
2、???授權擴展框架
最簡單的Guacamole認證擴展需要pom.xml文件、.java文件、guac-manifest.json文件。為簡單起見,使用Maven創建擴展。
首先,需要三個文件:
pom.xml文件列出guacamole-ext作為dependency
.java文件實現認證提供程序的功能
guac-manifest.json文件描述擴展并指向類“authenticationproviders”。
簡單實例創建的文件清單:
pom.xml
TutorialAuthenticationProvider.java
(位置src/main/java/org/glyptodon/guacamole/auth)
guac-manifest.json(位置src/main/resources)
?
3、???構建擴展
上述三個文件準備好,授權擴展就可以創建,可以安裝到Guacamole。創建授權擴展會生成target/guacamole-auth-tutorial-0.9.9.jar。
4、???配置和權限
當我們接收到認證消息,需要guacamole.properties中的相關屬性進行驗證。用戶名和密碼匹配時,授權擴展會讀取配置信息并存為GuacamoleConfiguration,返回配置信息,告訴Guacamole用戶已經通過認證。
簡單實例的屬性,定義在TutorialProperties.java:
tutorial-user
tutorial-password
tutorial-protocol
tutorial-parameters
?
5、???解析配置
從guacamole.properties文件讀取數據,如果認證通過,根據數據進行配置。
6、???安裝擴展
把需要的屬性添加到guacamole.properties,將生成的target/guacamole-auth-tutorial-0.9.9.jar復制到GUACAMOLE_HOME/extensions,重啟Tomcat。
七、??? 推送(todo)
?
?
八、???視頻流量優化(todo)
?
?
總結
以上是生活随笔為你收集整理的guacamole整体架构的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android - 键值对存储 Shar
- 下一篇: 计算机考试当场出分,基金从业资格考试当场