Posted on 2009-11-17 08:53
乱78糟 阅读(1891)
评论(0) 编辑 收藏 引用 所属分类:
重要资料
RFB (Remote Framebuffer)
為一種簡單的遠端存取協定,讓使用者以圖像的方式存取遠端電腦。此協定運作於Framebuffer層級,因此能夠應用於所有的視窗介面,其包括X11、Windows及Macintosh。VNC即是RFB協定一種應用。
要求連線,並得到遠端畫面的一方稱之為Client或是Viwer,對相的另一端稱之為RFB Server。RFB實為一種「Thin-Client」的協定,此重點在於建立一個功能上需求極精簡的Client,在這方面,Client可以應用於更廣泛的硬體上,而Client的功能愈簡單愈好。 RFB協定同時使得Client成為一種「stateless」的形態,假若Client中斷連結後,隨及再度連結同個Server,Client端的畫面將會保留。此外,不同的Client允許對同樣的RFB
Server做連結。在新的端點上的使用者會看到與Server主機相同的畫面,實際上,這樣的介面讓使用者更能夠任意的改變位置。不論如何,只要得到合
適的網路連線,使用者就能夠任意存取個人應用軟體,這些應用軟體能夠在兩地之間做到存取的動作,不過何處,都能提供使用者熟悉的、客製化的視覺基礎。
RFB內容還包括了以下各式協定:
Display Protocol
顯示協定的基礎圍繞在原始單一圖像(single graphics primitive):
『將某區塊的像素資料,設定至(x,y)位置上』
在
最初看來,以這種方式繪出使用者介面似乎會是個無效率的方法。然而,允許多種不同的編碼方式,對於像素資料處理中,交換參數值方面得到了相當大的使用彈
性,例如頻寬、Client繪圖速度、Server
處理速度等。 給定一串序列的資料可對Framebuffer做更新的動作。而每一次的更新,都會將舊有的Framebuffer更動至另一種狀態,這
方面有點類似一段影片中的影格(Frame),基本上每個區塊都不會相交,但還是會有不一定的狀況出現。 更新協定為一種「需求導向」的協定,意思是說
「在Client要求更新時,訊息只會由Server發送」,這方式使得此協定能有最合適的通訊品質,慢速Client會更新的較慢。一般應用程式在
Framebuffer相同區段改變時,會變換的較其他區段來的快速,若是在傳輸緩慢的網路中,Framebuffer的更新可能會被乎略掉。
Input protocol
輸入以標準工作工如鍵盤、多按鈕裝置為主。Client在任意地點,按下按鍵或是點座標裝置移動時,都會對Server發送要求訊息。這些被輸入的訊息亦可由非標準輸入裝置發送,整合為可被Server接受的編碼。
Display pixel data
RFB在
開始送傳資料前,Client及Server
會對將被傳送的像素資料的格式及編碼方式做協調,這部份的協調是為了讓Client端的工作愈簡單愈好,Server必需提供Client最基本的像素資
料的需求,假若
Client本身能夠應付其他多種編碼方式,Server則會選擇最簡單易行的編碼方式來做傳送的動作。 像素資料包函個別顏色內容,最普遍的顏色格式
如「真彩」的24-bit及16-bit,每個bit區段直接轉為RGB對應的強度色彩。 「編碼」(encoding)會影響區段內的像素資料如何傳
送,每個像素資料區塊都預先被指定一個(x,y)螢幕位置,而區塊的長、寬、編碼都將被指定在像素資料的資料區塊中,而區塊資料也會依據指定的編碼方式編
碼。
Extension protocol
在此有多種方法能夠擴展協定:
新增一個編碼的型態對於現有的Client及Server來說是相對上的容易做到,只不過Server會自動乎略它不支援的新編碼型態,而Client也不會去求要一個新的編碼方式,因此不會產生這種編碼方式的資料區塊。
編
碼資料中對於偽編碼(Pseudo
Encodings),Client可以對Server要求“pesudoencoding”,宣告其本身支援這一類型的擴充協定;假若Server不支
援”pseudo-encoding”則會略乎此編碼。該注意的是Client必需假設Server不支援這類的擴充,直到Client從Server取
得真正完成擴充認證。
新的安全型態
協定在新新增一個安全型態時有很大的彈性,而不必擔心Client及Server的相容性問題。當Client及Server 都這同了新的安全型態後,雙方在資料交換方面將更加有效率,並不見得每一項工作都需依照RFB協定。
在任何情況下使用不同版本的協定
RFB協定的版本主要被維護人員定訂,假若你的協定與Server使用了不正確的版本號碼,雙方將無法相容。最重要的一點在於確認RFB協定的相容性,以確保編碼及安全型態不會發生衝突。
協定訊息
RFB協定可以依任何可靠的定協傳送資料 (如TCP/IP),即使byte-streamor。正常來說RFB主要透過TCP/IP達成連線。完成一個RFB協
定有三個步驟:第一步為「handshaking
phase」,此階段主要是去同意協定的版本及使用的安全型態;第二步為「initialization
phase」,即對Server與Client互相交換「ClientInit」及「ServerInit」的訊息。第三步為「normal
protocol interaction」,Client將能夠傳送任何它想傳送的訊息,然後接受Server回傳的結果。
協定版本
「Handshaking Phase」開始前,Server會傳送ProtocolVerstion的訊息給Client,使得Client能夠知道Server端支援RFB的最高版本,隨而Client回應Server可使用的版本號碼(不一定與Server的版本號碼相同),正常來說,Client不該要求高於Server端RFB的版本。
安全
一
定協定版本確認後,Client、Server在連線時,必需協議共同的安全性標準。假若Client支援的安全性協定有在Server列舉的安全性協定
清單中,Client會回傳單一byte的訊息告知Server某安全性協定可被用於這次的連結。 在進行Handshaking
Phase時,不論這一階段的連成是否成立,Server都會傳送一個字串通知Client,假若連線成立,RFB協定即進行下一階段──Initialization Phase.
假若安全性連線失敗,Server則傳送一則字串描述此異常,隨後終止連結。
VNC認證
連線時,隨送傳送16位元的VNC認證,而協定資料不做加密的動作。Server會隨機產生一個16 byte的要求Client回應特定的訊息。Client依據Server傳送過來的16 byte編碼為金鑰,並加密回傳此金鑰以回應Server。而此更協定依據項些安全性協定的回應持續進行下去。
訊息初始化
當Client、Server建立安全性連結後,接著會進行初始化層段(initialsation phase)
這個階段,在Client傳送一個「ClientInit」,Server隨即會傳送「ServerInit」訊息。
ClientInit:
Client
回應的訊息只有一個「shared-flag」參數,若值非「0」(true),則表式Server試著去持續共享桌面而不對其他的Client端做終止
連線的動作,反之,若值為「0」(false),則表示終止其他連線,僅對某Client端提供桌面分享的服務。
ServerInit:
Server 接受ClientInit訊息後,會接著發送ServerInit訊息,此訊息會告知Client端Framebuffer的長、寬、像素格式以及此桌面相關名稱。
Client給Server的訊息內容
由Client所發出的訊息形態如下:
SetPixelFormat
SetEncodings
FramebufferUpdateRequest
KeyEvent
PointerEvent
ClientCutText
此外,其他仍有需要另行定義的訊息形態,需注意的是假如一則訊息形態沒有事先定義在Client的文件中,Client需確定Server傳送此特定的訊息形態後,Client仍能夠有效的支援。
Client端訊息
SetPixelFormat
設定像素資料後,接會會被置入Framebuffer中的FramebufferUpdate,假若Client沒有送出SetPixelFormat資料,Server在送出像素資料時將會依據即定的像素格式(格式請參考文件6.3.2)。
SetEncodings
指
定可被Server接受的編碼格式。而設定於送給Server訊息中的編碼格式將會是雙方做連結時,編碼格式的首選,但此編碼不一定會被Server選
擇。即使沒有明確指定,像素資料都會以row的方式被傳送。此外,Client可對原始編碼資料做「偽編碼」(pseudo-encodings)的要
求,以告知Server本地端支援此類型的擴充,假若Server不支援此「偽編碼」的類型則會直接乎略不使用。需注意的是,Client必需假設
Server端不支援Client原始的編碼型態,直到Server認同Client端的原編碼型態後,Client才能夠使用此編碼型態。
FramebufferUpdateRequest
Client
端對Server提出請求,以了解Server端寫入Framebuffer中的x-position、y-position、width、height
數值。Server會以「FramebufferUpdate」對Client端做回應,但需注意的是,多個
FramebufferUpdateRequest可能只會由單一一個FrameBufferUpdate回應。 Server會假設Client不斷
的截取存放在Framebuffer中Client所需求的部份(x-position,y-position,width,height),因此
Server僅需要對Client傳送不斷更新的部份。 但在某些狀況下,Client遺失某特別需求的部份,Client將傳送一則
「FramebufferUpdateRequest」訊息,其中參數incremental幫需設為「0」(false),這會對Server請求傳送
某指定的Framebuffer的全部內容。 假若Client沒有遺失Framebuffer中任何必要的部份,則傳送
FramebufferUpdateRequest時incremental的內容值將會是非0值(true),假若Framebuffer的內容有所更
新,Server亦會傳送一個FramebufferUpdate訊息。這裡需注意的是「雙方發某更新訊息的時間是不固定的」。 在快速網路的狀況
下,Client會去範規更新傳送的速度以避免獨佔頻寬。
KeyEvent
假若鍵盤按鍵按下,Framebuffer中
Down-flag參數值將會是非0值(true),反之則否。其中由X
Window所定義的「keysym」值,被指定用於KeyEvent,作為所謂的按鍵「key」。一般來說,這裡的keysym的key值等同於
ASCII所訂定的內容值。keysyms並不容易了解,為了提高keysyms能被廣泛的利用,需要注意以下事項:
1、「shift」的狀態
(不論shift是否被按下),在keysym動作時應該被視為「背景執行」。舉例來說,要按下US鍵盤的「#」需要按住「shite +
3」,但UK鍵盤則不需按下shift。假若server端為US鍵盤,想要從使用UK鍵盤的Client接收一個「#」號,Client將不會有
shift被按下的動作。在這狀況下,Server為了取得一個「#」而非數字「3」,將會內部將shift設為「已按下」。
2、在keysym
中,大小寫的區別常非重要。這不同於某些鍵盤於X
Window下將大小寫視為相同的狀況。例如,Server接收keysym值中的大寫「A」時,即使沒有按下shift也該認為是大寫的「A」,這代表
的是此時,server內部需假定已按下了shift。
3、Server應該呼略keysyms中的「lcok」,如CapsLock和NumLock,且應該依據不同的狀況來解釋每一個接收到的keysyms字元。
4、不同於shift的其他修飾鍵如「Ctrl」、「Alt」等,一樣需要用來反應keysyms值,要注意的是在keysyms中沒有如「ctrl+a」之類的值,這些值(ctrl、alert)只能在Client按下a後跟著被傳送出去。
5、
以Client端來說,當他們按下Ctrl或Alt時同樣會產生keysyms中的某些字元,而Client可能需要另外傳送「Release」事件以確
保傳送的keysym值能夠正確被Server了解。例如,在German
PC鍵盤上,「Ctrl+Alt+q」會產生「@」,在這狀況下,Client需要為「Ctrl」或「Alt」傳送一個假的「release
Ctrl」、「release Alt」訊息給 Server以確保keysym值正確被Server解釋。
6、在X
Window裡,「backword tab」並沒有通用的標準,在某些系統裡,shift+tab會產生「ISO Left
Tabe」的keysym值,其他系統則可能產生「Back
Tab」或僅僅產生「Tab」值,或是由應用程式從shift的狀態來判別「backword-tab」而不是「forward-tab」。在RFB協定採用最後一種方式,Client應該產生shifted Tab而不是ISO Left Tab。然而,為後符合backward-compatible的Client,Server應該懂得判別ISO Left Tab同於另一種shift Tab。
PointerEvent
標
示如「點的移動」或「點按鈕的按、放」等。點的位置設定於(x-position,y-position),而目前1~8的按鈕狀態由bits0~7的按
鈕遮罩所表示,0代表放開,1代表按下。以滑鼠來說,按鈕1、2、3分別對應至左鍵、中鍵、右鍵等。以有滾輪的滑鼠來說,每一個「向前滾動」的動作都代表
按下、放開「按鈕4」,向後滾動則以「按鈕5」來表示。
ClientCutText
Server訊息
Server to client messages
Server傳送給Client的訊息包函在下列變數中:
FramebufferUpdate
SetColourMapEntries
Bell
ServerCutText
需注意的是在傳送一則沒有定義於Server文件中的訊息前,Server需要從Client取得「extension specific」,以確定Client在接收後能夠支援此編碼,對此,通常會對Client要求一個偽編碼(pseudo-encoding)。
FramebufferUpdate
一
個FramebufferUpdate的內容主要包函一序列的像素矩陣資料(Client必需將這些像素資料填入Client端的
Framebuffer),而這一則命令主要在Client發出FramebufferUpdateRequest後產生,需注意的事Update及
UpdateRequest的發送時間並沒有明確的定義。
SetColourMapEntries
像素格式若使用「colour map」時,訊息將會告訴Client端其指定的像素值必需對應至指定的RGB強度。
Bell
觸發Client端的Bell物件(若Client有此物件)
ServerCutText
編碼
文件中所定義的編碼型態包括:
Raw
CopyRect
RRE
Hextile
ZRLE
Cursor pseudo-encoding
DesktopSize pseudo-encoding
各編碼內容:
Raw encoding
此為最簡單的編碼型態。此編碼主要包括width x height像素值(Server端產生的四方體,其長、寬的值),這兩項變數值表示每畫面的像素值,並由左至右做線性排列。所有的RFB Client必需能夠去處理Raw編碼中的像素資料。而RFB Server也應該只以Raw編碼為編碼方式,除非Client要求其他的編碼方式。
CopyRect encoding
CopyRect(copy
rectangle)編碼屬於簡單且有效率的編碼方式,能夠於Client在Framebuffer中有相同區塊的像素資料中使用。這項編碼方式會先在填
入Rect的X,Y標,這動作將使Framebuffer得到一個位置,隨後Client可以取得Rect的像素資料。這項編碼可以用於Client畫面
不斷變動狀況,當使用者移動某視窗,或是捲動視窗捲軸時,更能明顯看出此編碼的效果,但若用於對視窗最佳化、重繪圖像等動作時,就不會有明顯畫面變化的效
果。Server對圖像只做一次最正確的傳送是最正確的作法,接著要知道這個圖像先前於Framebuffer的位置(x,y),最後使用
CopyRect編碼傳送更新的Framebuffer敘述(subsequent)。
RRE encoding
RRE指
rise-and-run-length,其基礎在於模擬一段的二維編碼。RRE編碼所包函的rectangle會以能夠被簡易的繪圖engines有效
率而快速繪製的形式到達Client端。 RRE編碼的缺點在於無法適用於複雜的桌面,但仍能使用於某些狀況。RRE編碼的基礎在於分割某像素資料的
rectangle成多個副屬的rectangle,每一個副屬的rectangle都包括了各別區塊的像素內容,而將這些副屬的rectangle組合
後,將會得到原始的rectangel,這些最適的副屬區塊相對的容易被計算出來。這項編碼包括背景像素值,
Hextile encoding
Hextile
編碼為RRE的一種延伸,其將rectangle分成16 x 16的區塊,可令其大小為每邊區塊4
bit,而一個被化分出來的rectangle共16bit。每個rectangle由左上開始往右下計算,先左而右,由上至下,而編碼的內容都會依據先
前的rectangel排列模式做排列。假若一個rectangle的寬度並非16的倍數,則最後一個rectangel在劃份後的寬度將會小於16。高
度的原理同於寬度。 每個區塊不管以Raw編碼或是RRE編碼都會有背景像素值(background
pixel),若背景像素的數值同於前一區塊,則不需特別設定至新的區塊中。另一個狀況:若傳送資料是以Raw編碼,背景像素值則不需要做任何設定。假若
所有的副屬區塊(subretangle)都擁有相同的背景像素值,可當做整個區塊的前景顏色像素值,僅做一次性的設定;前景像素可同於背景像素的指定方
式,其不需特別設定至區塊中,可從前一個區塊中取得。假若先前的區塊是Raw或是SubrectColored的設定,當下的區塊就不會特別前景像素設定
至當下的區塊中,但會以AnySubrects從前一區塊取得前景像素(假定前一區塊已經從更前面的區塊取得前景像素值)。
ZRLE encoding
ZRLE代表的是Zlib1 Run-Length Encoding,擁有Z-lib的壓縮、劃分區塊的能力。在傳送的序列資料中,每個區塊由4 byte長的標頭開始,隨後接著由z-lib壓縮的資料。每個單z-lib序列物件主都會在RFB協
定的連結中產生作用,所以編碼、解碼需定訂嚴格的順序。 Z-Lib的資料在解壓後,會產生64 x
64的區塊,其值由左至右、由上至下排列(同於Hextile),若資料的長寬bit數不是64的倍數,則最後一個區塊的長寬將會小於64
bit。 ZRLE利用CPIXEL(compressed
pixel)技術,這方法同於一般的像素格式,其中所有的bit由(r,g,b)構成,不管(r,g,b)強度為何,true-colour-flag的
值不會是0,bitperpixel的值是32,depth值會在24以下。ZRLE中,一個CPIXEL只會有3
byte的長度,亦可能包函最低顯著或最高顯著的(r,g,b)值。bytePerCPixel為ZRLE中CPIXEL的bytes數。 每個區塊以
subbencoding type
byte開始,假若區塊編碼的起始byte有做過任何設定,則代表此區塊已運行過或是已被清除等等。區塊最底部的7個位元指定著色的範圍,0代表沒有做任
何著色;1代表區塊使用單一色系,2~127表示區塊共使用了多少的顏色。
Pesudo-encodings
Cursor pseudo-encoding
Client
若對Server發送這一則指令,即表示Client將有能力在本地端劃出server
mouse的位置,這能夠在慢速的連線中明顯提升畫面呈現的效果。Server傳送FreamebufferUpdate時,會同時在Cursor
pseudo-encoding設定pesudo-rectangle的內容回應Client的更新要求。pesudo-rectangle的內容包函
x-position及y-position,其指出server端Cursor的位置,而width、height分別為Cursor的像素,並依據
bitmask來設定資料的內容(所謂的bitmask,其內容主要是由左向右、由上至下對像素值做線性排列。
DesktopSize pseudo-encoding
Client
端對Server請求DesktopSize
pseudo-encoding以告知本地端可應付Framebuffer中width、height值變動的狀況。Server通常會將這一個
pseudo-rectangle設定至最後一個Framebuffer資料的DesktopSize
pseudo-encoding中,而此項目中pesudo-rectangle的x-position及y-position會被乎略,width及
height值會告知新的Framebuffer大小。