一,簡介
RFB ("remote 幀緩存")
是一個遠程圖形用戶的簡單協議,因爲它工作在幀緩存級別上,所以它可以應用於所有的窗口系統,例如:X11,Windows
和 Mac 系統。其中VNC(Virtual Network Comp uting)
就採用RFB.
遠程終端用戶使用機器(比如顯示器、鍵盤/鼠標)的叫做RFB客戶端,提供幀緩存變化的被稱爲RFB服務器。
RFB 是真正意義上的“瘦客機”協議。RFB協議設計的重點在於減少對客戶端的硬件需求。這樣客戶端就可以運行在許多不同的硬件上,客戶機的任務實現上就會盡量的簡單。RFB協議對於客戶端是無狀態的。也就是說:如果客戶端從服務器端斷開,那麼如果它重新連接相同的服務器,客戶端的狀態會被保存。甚至,一個不同的客戶端可以用來連接相同的RFB服務器。而在新的客戶端已經能夠獲得與前一個客戶端相同的用戶狀態。因此,用戶的應用接口變的非常便捷。只要合適的網絡連接存在,那麼用戶就可以使用自己的應用程序,並且這些應用會一直保存,即使在不同的接入點也不會變化。這樣無論在哪,系統都會給用戶提供一個熟悉、獨特的計算環境。
二,顯示協議
顯示協議是建立在“把像素數據放在一個由x,y
定位的方框內”這單一圖形基礎之上的。乍一看上去,把這麼多的用戶接口組件繪製出來是非常低效的方法。但是允許不同的像素數據編碼方式,使得我們在處理不同的參數(如:網絡帶寬,客戶端的繪製速度,服務器處理速度)有了很大程度的靈活性。通過矩形的序列來完成幀緩存的更新。一次更新代表着從一個可用幀緩存狀態轉換到另一個可用,因此有點和視頻的楨類似。儘管矩形的更新一般是分開的,但是並不是必須的。顯示協議的更新部分是由客戶端通過命令驅動的。也就是說,更新只是在服務器端響應客戶端的請求時發生的。這樣就讓協議更新質量是可變的。客戶端/網絡越慢,更新速度也就越慢。對於一些應用來說,相同區域的更新是連續不斷的。如果用一個慢的客戶端,那麼幀緩存的緩存狀態是可以被忽略的。這樣也可以減少對客戶端網絡速度和繪製速度的要求。
三,輸入協議
輸入協議是基於標準工作站的鍵盤和鼠標等設備的連接協議。輸入事件就是通過把客戶端的輸入發送到服務器端。這些輸入事件也可以通過非標準的I
/O 設備來綜合。例如,手寫筆引擎可能產生一個鍵盤事件。
四,像素數據的重現
初始的交互涉及到RFB客戶端和服務器之間傳輸像素數據格式和編碼方式的協調。這種協調被設計的讓客戶端的工作儘量簡單。而設計的底線是:服務器必須按照客戶端的要求格式來提供像素數據。如果客戶端可以同樣的處理多種數據格式或編碼格式,那麼一般會選擇服務器端易於生成的格式。像素格式涉及如何通過像素值來實現不同顏色的重現。最常用的一般像素格式是24
位或16 位的“真彩色”,它通過位來直接實現像素值到紅、綠、藍亮度的轉換。8
位“顏色映射”可以任意映射像素值到RGB亮度的轉換。編碼解決像素數據如何通過網絡傳輸的問題。每一個矩形像素數據都帶有數據的X,Y參數,寬和高是矩形,編碼類型確定像素數據的編碼方式。數據本身遵循特定的編碼。目前的編碼方式主要有Raw、CopyRect、RRE、Hextile
和ZRLE.在實際應用中我們一般使用ZRLE、Hextile
和CopyRect,因爲它們提供了典型桌面的最好壓縮。(參照6.6
關於每種編碼方式的描述)
五,協議擴展
協議可以通過以下方式進行擴展:
1)新的編碼方式
一種新的協議可以通過與現存的客戶端和服務端進行相關兼容的添加。因爲現存的服務器將會忽略它們所不支持的新編碼方式。所以客戶端通過新的編碼方式進行請求也就不會有結果返回。
2)僞編碼方式
除了真正的編碼方式,客戶端也可以請求“僞編碼”通告服務器,它支持某一協議的擴展。服務器如果不支持這種擴展,那麼它將忽略。值得注意的是:客戶端必須先假設服務器端不支持這種擴展,直到它獲得服務器端支持的確認。(參照6.7
僞編碼的描述)
3)新的安全方式
添加一個新型的安全方式會帶來無限的靈活性,它通過修改協議的一些行爲,但是並沒有犧牲現存客戶端和服務器端的兼容性。客戶端和服務器端可以通過協議好的安全方式進行交流,當然並不一定與RFB協議類似。無論如何你都不應使用不同的版本號RFB協議的版本是由RealVNC公司來制定的。如果你使用一個不同的協議版本可能與RFB/VNC兼容,要保證協議的兼容性,請聯繫RealVNC公司。這樣會減少在編碼方式和安全類型上的衝突。請登陸h
t t p: / /www.realvnc.com 查看我們的聯繫方式,加入VNC郵件列表也是一個很好的選擇。
六,協議消息
RFB協議可以進行可靠的傳輸,如字節流或基於消息的。和大多數協議一樣,它也是通過TCP /IP協議簇連接。協議由三步完成連接。首先是握手報文,目的是對協議版本和加密方式進行協商。第二步是初始化報文,主要用於客戶和服務器的初始化消息。最後就是正常協議的交互,客戶端可以按需發送消息,然後可以獲得服務器的回覆。所有的消息以消息類型開始,接下來是特定的消息數據。協議消息描述的基本類型有:U8、U16、U32、S8、S16、S32。U表示無符號整數,S表示有符號整數。所有字節整數(除了像素值本身)遵從Endian
順序。PIXEL代表一個像素值bytesPerPixel
字節,8XbytesPerPixel =bi t s - per - pixel,這個等式在客戶端/服務器ServerIni
t 消息(參照6.3.2
節)、SetPixelFormat
消息(參照6.4.1
節)中是被承認的。
1)
握手消息
1> 協議版本
握手始於服務器向客戶發送協議版本的消息,以告知客戶服務器所能支持RFB協議的最高版本號。此時客戶端會發送相似的消息告訴服務器將要使用的協議版本。客戶端不應該請求高於服務器的協議版本。如此一來就給客戶和服務器端提供了一種向後兼容機制。目前發佈的協議版本主要有3.3、3.7、3.8(3.5
版本被報告存在問題),對於新的編碼和僞碼方式版本號不需要進行修改,因爲服務器端可能忽略它不能識別的版本。協議版本消息由12
字節的ASCII碼串組成,它的格式"RFB xxx.yyy \ n",其中xxx
和yyy 分別是主要和次的版本號,並用0
進行補充。
2>
安全
一旦協議版本被確定,服務器和客戶端必須一致同意連接的安全類型。V3.7
向上 服務器支持的安全類型:
字節數 |
|
描述 |
1 |
U8 |
安全類型號 |
安全類型號 |
U8 |
安全類型 |
如果客戶端能支持服務器的某一安全類型,那麼客戶端就會發送一個字節來確認連接的安全類型:
字節數 |
|
描述 |
1 |
U8 |
安全類型 |
如果安全類型號是0,那麼連接失敗(例如服務器不支持客戶請求版本號),這樣就會有字符串來描述失敗原因:
字節數 |
|
描述 |
4 |
U32 |
原因長度 |
原因長度 |
U8數組 |
原因字串 |
服務器在發送原因字串後就會關閉連接。V3.3 服務器決定安全類型併發送一個字:
字節數 |
|
描述 |
4 |
U32 |
安全類型 |
安全類型的值一般有0、1、2。0
表示連接失敗,並伴隨原因字串。本文中定義的安全類型有:
0 :
不可用
1 : NONE
2 : VNC
認證
5
: RA2
6 : RA2ne
16: Tight
17: Ultra
18: TLS
19: VeNCrypt
安全類型確定,數據遵循安全類型的定義(詳情參見6.2)。安全握手報文的末端,一般伴隨着安全結果消息。
注意:在安全握手報文之後,很有可能是其他協議數據經過加密或者被修改的通道。
3>
安全結果
服務器發送一個字告訴客戶端安全握手成功。
字節數 |
|
描述 |
4 |
U32 |
狀態 |
0 |
成功 |
|
1 |
失敗 |
如果成功,協議進入初始報文(第6.3
節)V3.8 以上版本如果不成功,就會有字符串來描述失敗原因,並關閉連接:
字節數 |
|
描述 |
4 |
U32 |
原因長度 |
原因長度 |
U8數組 |
原因字串 |
對於V3.3 和 3.7 如果不成功,服務器直接關閉連接。
2)安全類型
1> NONE
不需要認證,協議數據將被使用明文發送。V3.8
以上版本,還會帶有安全結果的消息。V3.3
和 3.7 協議直接進入初始報文(參照6.3).
2>VNC認證
採用VNC認證,協議數據將採用明文發送,服務器發送一個16
字節的隨機數驗證:
字節數 |
|
描述 |
16 |
U8 |
驗證 |
客戶端使用DES對驗證進行加密,使用用戶密碼作爲密鑰,把16 字節的回覆返回到服務器:
字節數 |
|
描述 |
16 |
U8 |
驗證 |
隨之而來的就是安全結果消息。
3)初始化消息
一旦客戶和服務器都同意使用同一安全類型進行交流,那麼協議進入初始化消息。客戶端發送一個客戶初始化消息,緊接着就是服務器初始化消息。
1> 客戶端初始化
字節數 |
|
描述 |
1 |
U8 |
共享標誌 |
如果服務器同意其他客戶繼續連接,那麼共享標誌應該是非零(真)。否則,服務器將斷開其他客戶的連接。
2>服務器初始化
服務器收到客戶端初始化的消息後,會發送一個服務器初始化消息。主要是告知客戶端服務器上幀緩存的高寬,像素格式還有與桌面相關的名稱。
字節數 |
類型【值】 |
描述 |
2 |
U16 |
幀緩存寬度 |
2 |
U16 |
幀緩存高度 |
16 |
像素格式 |
服務器像素格式 |
4 |
U32 |
名字長度 |
名字長度 |
U8數組 |
名字字串 |
像素格式主要包括以下段:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -- - - - - - - - - - -
字節數 |
類型 [ 值 ] |
描述
- - - - - - - - + - - - - - - - - - - - + - - - - - - - -- - - - - - - - - -
1 | U8 | 位/像素
- - - - - - - - + - - - - - - - - - - - + - - - - - - - -- - - - - - - - - -
1 | U8 |
深度
- - - - - - - - + - - - - - - - - - - - + - - - - - - - -- - - - - - - - - -
1 |U8 | big - en dian
標誌
- - - - - - - - + - - - - - - - - - - - + - - - - - - - -- - - - - - - - - -
1 | U8 |
真彩標誌
- - - - - - - - + - - - - - - - - - - - + - - - - - - - -- - - - - - - - - -
2 | U16 |
紅色最大值
- - - - - - - - + - - - - - - - - - - - + - - - - - - - -- - - - - - - - - -
2 | U16 |
綠色最大值
- - - - - - - - + - - - - - - - - - - - + - - - - - - - -- - - - - - - - - -
2 | U16 |
藍色最大值
- - - - - - - - + - - - - - - - - - - - + - - - - - - - -- - - - - - - - - -
1 | U8 |
紅色-替換
- - - - - - - - + - - - - - - - - - - - + - - - - - - - -- - - - - - - - - -
1 | U8 |
綠色-替換
- - - - - - - - + - - - - - - - - - - - + - - - - - - - -- - - - - - - - - -
1 | U8 |
藍色-替換
- - - - - - - - + - - - - - - - - - - - + - - - - - - - -- - - - - - - - - -
3 | |
補充
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -- - - - - - - - - - -
服務器象素定義服務器本來的象素格式,這種象素格式會被一直使用,除非客戶端使用設置象素格式消息來請求另一種象素格式。(參照 6.4.1)位每象素表示每一個象素值對應的位數,它必須大於等於每個象素值。目前位每象素必須是8,16
或32——小於8
位象素不被支持。如果多字節象素被看做big en dian,那麼Big -en dian
標誌非零。當然了,這對8
位每象素沒有任何意義。如果真彩標誌非零,那麼最後6
項規定如何按照象素值來確定紅、綠、藍的亮度。紅的最大值是紅色的最大值(=2 ^n - 1, n
表示用在紅色上的位數)。注意這個值一般在big endian的順序中。紅色-替換表示要得到最低明顯bit
所需要的替換個數。綠色最大值、綠色-替換和藍色最大值、藍色-替換和紅色類似。要在0—紅色最大值之間找一個紅色值,按照以下步驟進行:
• 遵循big - en dian
標誌進行象素值。(例如:如果big - endian
標誌爲0,主機的字節順序是big endian,然後交換)。
• 使用紅色—替換將右邊替換。
• 和紅色最大值進行邏輯與(按照主機字節順序)。
如果真彩標誌是零,那麼服務器使用的象素值不是直接由紅、綠、藍的亮度組成,但是服務爲索引到顏色圖中去。顏色圖中的項目是由服務器使用“設置顏色面板條目”消息進行設置的。
4)客戶到服務器消息
客戶到服務器的消息在本文中有如下定義:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -- - - -
號碼 |
名稱
- - - - - - - - - - + - - - - - - - - - - - - - - - - - -- - -
0 | 設置象素格式
- - - - - - - - - - + - - - - - - - - - - - - - - - - - -- - -
2 | 設置編碼
- - - - - - - - - - + - - - - - - - - - - - - - - - - - -- - -
3 | 幀緩存更新請求
- - - - - - - - - - + - - - - - - - - - - - - - - - - - -- - -
4 | 按鍵事件
- - - - - - - - - - + - - - - - - - - - - - - - - -- - - - - -
5 | 鼠標事件
- - - - - - - - - - + - - - - - - - - - - - - - - - - - -- - -
6 | 客戶剪切文本
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -- - -
其餘的註冊消息類型有:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -- - -
號碼 |
名稱
- - - - - - - - - - + - - - - - - - - - - - - - - - - - -- -
255 | Anthony Liguori
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -- -
值得注意的是:如果要發送未在本文中定義的消息,那麼必須得到服務器端的消息確認。
1>設置象素格式
“幀緩存更新”消息中設置什麼格式的象素值如何設置。如果客戶端沒有發送“設置象素格式”消息,那麼服務器發送的象素值將遵循在服務器初始化消息中所包括的象素格式(參照6.3.2)。如果真彩標誌是零,那麼意味着使用“顏色面板”,只要客戶端發送顏色面板空的消息,或者是面板項被服務器端重設,服務器可以使用設置顏色面板項目進行顏色面板的設置(參照6.5.2)。
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -- - - - - - - - - - -
字節數 |
類型 [ 值 ] |
描述
- - - - - - - - + - - - - - - - - - - - + - - - - - - - -- - - - - - - - - -
1 | U8 0 |
消息類型
- - - - - - - - + - - - - - - - - - - - + - - - - - - - -- - - - - - - - - -
3 | | 填充
- - - - - - - - + - - - - - - - - - - - + - - - - - - - -- - - - - - - - - -
16 | 象素格式 |
象素格式
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -- - - - - - - - - - -
注:其中的象素格式如在6.3.2
中的描述
2>設置編碼方式
設置編碼方式可以來確定服務器發送象素數據的類型。消息中編碼方式的順序是客戶端按照優先級來排列(第一個擁有最高的優先級)。服務器可能選擇這種順序,也可能不選擇。象素數據也可以使用“原始編碼”如果沒有具體說明。除了基本的編碼方式,客戶端也可以請求“僞編碼”通告服務器它支持某一種擴展協議。如果服務器不支持這種擴展,它就會忽略這種僞編碼。注意:這意味着客戶端在得到服務器的確認之前都要假設服務器並不支持它的擴展。
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -- - - - - - - - - - -
字節數 |
類型[ 值 ] |
描述
- - - - - - - - - - + - - - - - - - - - - - - - - - - + -- - - - - - - - - -
1 | U8 2 |
消息類型
- - - - - - - - - - + - - - - - - - - - - - - - - - - + -- - - - - - - - - -
1 | |
填充
- - - - - - - - - - + - - - - - - - - - - - - - - - - + -- - - - - - - - - -
2 | U16 |
編碼編號
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -- - - - - - - - - - -
接下來就是編碼編號的重複
- - - - - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - - - - - - -
字節數 |
類型[
值] |
描述
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
4 | S32 |
編碼類型
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3>幀緩存更新請求
客戶端只在乎幀緩存區域的x、y、寬度和高度。服務器一般通過發送幀緩存更新來響應更新請求。當然,有可能一個幀緩存更新可能是多個請求的響應結果。通常服務器假設客戶端有所有它所感興趣的幀緩存,因此服務器只需要進行增量更新就OK了。但是如果因爲某種原因,客戶端丟失某一部分必須的內容,那麼它發送幀緩存更新請求的時候就會將增量設置爲零。這樣就會請求服務器儘快把所需內容進行發送。而這塊不會使用CopyRect
編碼方式進行更新。反之,客戶端就會增量設置爲非零。如果只是在特定區域發生改變,那麼服務器就會發送幀緩存更新。注意:在請求和更新之間可能存在不確定時間段。在客戶端比較快的情況下,客戶端有可能會規定增量請求的速率,這樣可以避免無端佔用網絡。
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
字節數 |
類型[
值] |
描述
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
1 | U8 3 |
消息類型
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
1 | U8 |
增量標誌
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
2 | U16 | x
座標
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
2 | U16 | y
座標
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
2 | U16 |
寬度
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
2 |U16 |
高度
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
4> 按鍵事件
某一個鍵的按下與釋放。如果某一個鍵被按下,那麼按下標誌非零。釋放的時候變爲零。在X Window
系統中鍵本身被賦值爲“keysym”。
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
字節數 |
類型[
值] |
描述
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
1 | U8 4 |
消息類型
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
1 | U8 |
按下標誌
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
2 | |
補充
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
4 | U32 |
鍵號
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
對於大多數鍵來說,“keysym”與ASCII碼相對應,具體參考《The
Xlib ReferenceManual》或者參考<X11 / keysysmdef.h>。部分按鍵對應如下:
解釋keysyms
是一個非常複雜的過程,爲了能夠儘量廣泛的使用,我們應該遵守以下指導意見:
• “切換狀態”(例如:切換是否按下)必須只能用於解釋keysym。例如,在美式鍵盤上,“#”是需要按下Shift,而英式鍵盤就不需要。對於一個使用美式鍵盤的服務器就不會返回“#”來自於英式鍵盤的請求,因爲它沒有使用“Shift”,這樣的話,看起來服務器應該“洗掉”shif
t 爲了獲得“#”。
• 大小寫的差別對於keysyms
非常明顯的。而在處理中不應該將它們同等對待。比如:“A”服務器應該不用按下Shift
就將它解釋爲“A”。這又涉及到“洗掉”Shift按鍵的問題。
• 服務器應該儘可能忽略“lock”,例如CapsLock和NumLock。取而代之的是根據字符來判斷它的大小寫。
•和s hif t
不同,修改狀態的按鍵,比如Ctrl
和Alt應該看做修改其他的keysyms。我們注意到在ASCII中沒有像“Ctrl
- a”類似的控制碼,所以應該通過客戶端來發送。
•對於客戶端,Ctrl
和Alt
也應該基於子房來判斷,因爲客戶端可能“釋放”來讓keysyms來正確的解釋。例如,在德國的個人計算機鍵盤中,ct
rl +al t +q 產生@字符,這樣的話,我們必須讓客戶端正確的輸入。
•在X window
系統中沒有統一的“Backward”按鍵,在某些系統中,s hif t +t ab產生“ISO_Left_Tab”,而在其他可能提供一個“BackTab”,也有“Tab”
和應用來告訴服務器shif t
的狀態表示backward - tab
而不是forward- tab。在RFB協議中更接近後者的實現方式。客戶端應該產生一個切換Tab
而不是“ISO_Left_Tab”.儘管如此,爲了與目前客戶端向後兼容,服務器應該把ISO_Left_Tab
看做爲變換的Tab鍵。
5>
鼠標(指針)事件檢測指針移動或者某一個鍵的按下或釋放。指針目前在(x座標、y
座標),按鈕的1到8
狀態通過0
到7位來表示,0
表示鬆開,1
表示按下。拿普通鼠標來說,1,2,3分別響應左、中、右鍵。對於滑輪鼠標來說,滾輪向上表示4鍵的按下和釋放,而向下表示5
鍵的按下和釋放。
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
字節數|
類型[值 ] |
描述
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
1| U8 5 | 消息類型
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
1| U8 | 按鍵屏蔽
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
2| U16 | x 座標
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
2| U16 | y 座標
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
6>客戶端文本剪切
客戶端有新的ISO8859 - 1(Latin - 1)
文本在它的剪切緩存裏,行的末尾通過新行字符(值爲10)來表示。需要無回車(值爲13)。目前還沒有找到傳輸非Latin
- 1 字符集的方法。
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
字節數 |
類型[值 ] |
描述
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
1 | U8 6 |
消息類型
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
3| |
填充
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
4| U32 | 長度
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
長度| U8
數組|
文本
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
5)
服務器到客戶消息
服務器到客戶消息在本文中定義如下:
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
號碼|
名稱
-- - - - - - - - - + - - - - - - - - - - - - - - - - - - - - -
0| 幀緩存更新
1| 設置顏色面板條目
2| 響鈴
3| 服務器剪切文本
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
其餘註冊的消息類型:
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
號碼|
名稱
-- - - - - - - - - + - - - - - - - - - - - - - - - - - - - - -
255| Anthony Liguorui
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
注意在服務器發送消息之前必須確認客戶端支持相關擴展,通常在請求“僞編碼”的時候使用。
1> 幀緩存更新
幀緩存更新是由一系列像素數據矩形而組成,這些矩形會被客戶端送入它的幀緩存中。它是對客戶端幀緩存更新請求的響應。而在請求和響應之間有可能存在不確定時期。
字節數 |
|
描述 |
1 |
U80 |
消息類型 |
1 |
填充 |
|
1 |
U16 |
矩形編號 |
隨着像素數據矩形的個數,每個矩形包括以下內容:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
字節數|
類型[值 ] |
描述
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
2| U16 | x 座標
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
2| U16 | y 座標
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
2| U16 | 寬度
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
2| U16 | 高度
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
4| S32 | 編碼類型
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
對應像素數據也是由特定的編碼方式,參照6.6(編碼的數據格式)參照6.7(僞編碼的含義)
2> 設置顏色面板條目
當像素格式使用“顏色面板”時,消息告訴客戶端對應像素值如何映射爲RGB亮度。
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
字節數|
類型[值 ] |
描述
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
1| U8 1 | 消息類型
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
1| | 填充
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
2| U16 | 第1
種顏色
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
2| U16 | 顏色數
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
對應顏色數字:
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
字節數|
類型[值 ] |
描述
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
2| U16 | 紅
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
2| U16 | 綠
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
2| U16 | 藍
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3>響鈴
如果有響鈴事件,就在客戶端上響鈴。
CopyLeftTrans By:曉風
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
字節數|
類型[值 ] |
描述
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
1| U8 2 | 消息類型
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
4>服務器剪切文本
同客戶端剪切文本(參照6.4.6)
6 )編碼
本文中定義的編碼類型如下:
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
號碼|
名稱
-- - - - - - - - - + - - - - - - - - - - - - - - - - - - - - -
0| Raw
1| CopyRect
2| RRE
5| Hextile
16| ZRLE
-239 | Cur sor 僞編碼
-223 | Deskto pSize 僞編碼
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
其餘註冊的編碼方式:
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
號碼|
名稱
-- - - - - - - - - + - - - - - - - - - - - - - - - - - - - - -
4 | CoRRE
6,7,8 | zlib, tight, zlibhex
-272 to - 257 | Anthony Liguori
-256 to - 240 |
-238 to - 224 |
-222 to - 1 | tight 選項
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1> Raw 編碼
最簡單的編碼類型就是Raw
像素數據,這種情況下,數據是由寬X高組成的(寬、高分別表示矩形的寬高)。像素值就是簡單的通過從左到右的掃描順序來反映。所有的RFB客戶端必須能夠處理使用Raw
編碼的像素數據,並且RFB服務器只能發送Raw編碼的數據,除非客戶端特別聲明要求其他的編碼方式。
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
字節數|
類型[值 ] |
描述
-- - - - - - - - - - - - - - + - - - - - - - - - - - - - - - + - - - - - - -
寬x
高x
字節/象素| PIXEL
數組 |
象素
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2>CopyRect 編碼
CopyRect 編碼方式對於客戶端在某些已經有了相同的象素數據的時候是非常簡單和有效的。這種編碼方式在網絡中表現爲x,y
座標。讓客戶端知道去拷貝那一個矩形的象素數據。它可以應用於很多種情況。最明顯的就是當用戶在屏幕上移動某一個窗口的時候,還有在窗口內容滾動的時候。在優化畫的時候不是很明顯,一個比較智能的服務器可能會發送一次,因爲它知道在客戶端的幀緩存裏已經存在了。接下來使用CopyRect
編碼方式發送相同的式樣。
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
字節數|
類型[值 ] |
描述
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
2| U16 | x 源位置
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
2| U16 | y 源位置
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3>RRE編碼
RRE表示提升和運行長度,正如它名字暗示的那樣,它實質上表示二維向量的運行長度編碼。RRE把矩形編碼成可以被客戶機的圖形引擎翻譯的格式。RRE不適合複雜的桌面,但在一些情況下比較有用。RRE的思想就是把像素矩形的數據分成一些子區域,和一些壓縮原始區域的單元。最近最佳的分區方式一般是比較容易計算的。編碼是由像素值組成的,Vb(基本上是在矩形中最常用的像素值)和一個計數N,緊接着是N的子矩形列表,這些裏面由數組<v,x,y,w,h
>組成,(x,y)是對應子矩形的座標,表示子矩形上-左的座標值,(w,h)
則表示子矩形的寬高。客戶端可以通過繪製使用背景像素數據值,然後再根據子矩形來繪製原始矩形。在傳輸中,數據以下列描述開始;
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
字節數 |
類型[值 ] |
描述
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
4 | U32 |
子矩形數目
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
字節每象素 | PIXEL |
背景象素值
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
對應子矩形的結構如下:
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
字節數 |
類型[值 ] |
描述
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
字節每象素 | PIXEL |
子矩形象素值
2 |U16 | x - posi tion
2 |U16 | y - posi tion
2 |U16 |
寬
2 |U16 |
高
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
4>Hextile 編碼
Hextile 是RRE編碼的變種,矩形被分割成16x16
小片,允許每個小片的維數爲4
位,總共16位。矩形被分割的小片從上開始,遵守自左到右,自頂向下的順序。小片的編碼內容按照預定的順序進行編碼。如果整個矩形的寬度不是16
的整數倍,那麼每行最後的小片也相應減少。高度也類似。每個小片可以使用raw
編碼,也可以是RRE編碼的變種。每個小片有一個背景像素值。但是,如果小片的背景像素值和前一個小片相同,那麼就不需要明確定義。如果小片的子矩形有相同的像素值,那麼前景像素值就可以只定義一次。和背景像素值一樣,前景像素值也可以通過前一個小片獲得。因此由小片組成的數據是按照順序進行編碼的。每一個小片以子編碼類型的字節開始。它是位數的屏蔽組成。
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
字節數|
類型[值 ] |
描述
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
1| U8 | 子編碼掩碼:
|1 | Raw
|2 | 背景定義
|4 | 前景定義
|8 | 任意子矩形
|16 | 子矩形着色位
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
如果Raw
位被設置,那麼其餘的位就無效;接着是寬X高像素值(寬和高是小片的寬高)。否則其他的位就有效。背景定義-如果設置,那麼像素值就會跟着小片的背景色:
- -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
字節數 |
類型[
值 ] |
描述
- -- - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
字節每象素 | PIXEL |
背景象素值
- -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
在矩形中的第一片非Raw
小片必須設置這一位,如果不設置,那麼它的背景就會和上一片相同。前景定義-如果設置,那麼像素值就會定義小片中所有子矩形的前景色。
- -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
字節數|
類型[
值 ]|
描述
- -- - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
字節每象素| PIXEL |
前景象素值
- -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
如果這一位被設置,那麼子矩形着色位必須爲0。任意子矩形-如果設置,那麼一個字節包含着子矩形的個數。
- -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
字節數 |
類型[
值 ] |
描述
- -- - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
1 |U8 |
子矩形數目
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
如果這一位不設置,那麼就不會有子矩形。(例如,整個小片就是背景顏色)子矩形着色-如果設置,那麼任意子矩形的像素值的優先級都高於子矩形的顏色定義,
因此子矩形是:
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
字節數|
類型[值 ] |
描述
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
字節每象素|PIXEL |
子矩形象素值
1 | U8 | x - an d - y - posi tion
1 | U8 |
寬和高
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
如果不設置,所有子矩形都是前景色的顏色,如果前景定義沒有設置,那麼前景色和前一個片的相同。子矩形就是:
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
字節數 |
類型[值 ] |
描述
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
1 | U8 | x - an d - y - posi tion
1 | U8 |
寬和高
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
每一個子矩形的位置和大小都是使用兩位進行定義,x - an d - y - posi tion
和width-an d - height。最重要的四位x - an d - y - posi tion
定義X的位置,不重要的定義Y位置。最重要的四位width
- an d - height 定義寬度-1,不重要的定義高度- 1。
5 >ZRLE編碼
ZRLE(Zlib Run - Length Encoding),它結合了zlib壓縮,片技術、調色板和運行長度編碼。在傳輸中,矩形以4
字節長度區域開始,緊接着是zlib
壓縮的數據,一個單一的zlib“流”對象被用在RFB協議的連接上,因此ZRLE矩形必須嚴格的按照順序進行編碼和譯碼。
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
字節數 |
類型[值 ] |
描述
-- - - - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - -
4 | U32 |
長度
長度 | U8 ar ray | zlibData
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
zlibData 在沒有壓縮之前,代表了由64x64
像素組成的從左到右,從高到低的順序的片,和hextile
編碼有點類似。如果整個矩形的寬度不是64
的整數倍,那麼每行最後的小片也相應減少。高度也類似。ZRLE編碼利用了一種新的壓縮像素CPIXEL(Compres
se dPIXEL)。這個和PIXEL有着相同的像素格式,除了真彩標誌是非零,位每像素是32,色深不大於24。所有的位組成紅,綠和藍的亮度填充最不重要的或最重要的三字節。如果CPIXEL只有3
字節長,並且包含有合適的最不重要或最重要3
字節。那麼bytesPerCPixel
就是CPIXEL的字節數。每片都是以子編碼類型字節開始,如果片被使用運行長度編碼,那麼本字節的最高位就會被設置。其餘7
位表示繪圖樣式-零表示沒有樣式,1表示片爲單色,2
- 127 表示對應的樣式。可能的子編碼值如下:
0 - Raw
像素數據寬X高像素值(寬和高爲對應片的寬和高,對應像素值如下:
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
字節數 |
類型[
值 ] |
描述
-- - - - - - - - - - - - - - - - + - - - - - - - - - - - - - + - - - - - - -
寬x
高x
字節/CPIXEL | CPIXEL
數組 |
象素
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1 -單色的片,對應像素值如下:
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
字節數 |
類型[
值 ] |
描述
-- - - - - - - - - - - - - - - - + - - - - - - - - - - - - - + - - - - - - -
字節/CPIXEL | CPIXEL
數組 |
象素
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2 - 16 -打包的樣式類型。對應像素值是由palet teSize(=子編碼)像素值,打包像素值組成,每個打包像素值表示爲一位區域服從樣式索引(0
表示第一個條目),對應palet teSize 2,1位被使用,palet
teSize 3,4有兩位被使用,從5 - 16
均有4
位區域被使用。位的區域被打包成字節,最重要的位表示最左邊像素。因爲片並不是8,4,2
像素寬的乘積,所以填充位被用來按照字節數排列每一個行。
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
字節數 |
類型[
值 ] |
描述
-- - - - - - - - - - - - - - - - + - - - - - - - - - - - - - + - - - - - - -
調色板x
字節/CPIXEL | CPIXEL
數組|
調色板
-- - - - - - - - - - - - - - - - + - - - - - - - - - - - - - + - - - - - - -
m | U8
數組 |
打包象素
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
m 表示打包像素的字節數。對於palet teSize 2
就是floor((width+ 7) / 8) x height,相應3,4
就是floor((width+ 3) / 4) x height,而5 - 16
就是floor((width+ 1) / 2)x
height。17- 127
未使用(對於palette RLE並沒有什麼優勢)。128
-簡單RLE它由一些不斷重複的執行組成,一直到片結束。執行可能從一行的結束到另一行的開始。每一次運行是通過一個像素值和像素值長度來表示的。長度一般爲1
個或多個字節。經過計算多於所有字節總和+ 1
作爲長度。除了255
任何字節值都隱含最後的字節。例如長度1
表示爲[0],255表示爲[254],256
表示爲[255,0],257表示爲[255,1],510表示爲[255,254],511表示爲[255,255,0]等等。
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -- - - - - - - -
字節數 |
類型 [
值] |
描述
-- - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - + - -- - - - - -
字節/CPIXEL | CPIXEL
數組 |
象素值
floor((runLength- 1) / 255) | U8
數組255 |
1 | U8 |( runLength - 1)%255
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -- - - - - - -
129-未使用
130 - 255 調色RLE。調色緊跟其後,由paletteSize = (subencoding -
128) 像素值組成:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -- - -
字節數|
類型[
值 ] |
描述
-- - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - + - - - - -- -
調色板大小x
字節/CPIXEL | CPIXEL
數組|
調色板
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -- -
接下來就合簡單RLE相似,一些不斷重複的執行組成,一直到片結束。執行長度通過調色板索引來表示。
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -- - -
字節數|
類型[
值 ] |
描述
-- - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - + - - - - -- -
1| U8 |調色板索引
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --
如果執行長度使用多於一位來表示調色板索引,並且最高位被設置。那麼就會帶有執行長度。
- - - - - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
字節數 |
類型 [
值] |
描述
-- - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - + - - - - -- -
1 | U8 |
調色板索引+ 1 2 8
floor((runLength- 1)=255) | U8
數組 255 |
1 | U8 |(runLength – 1)%255
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -- -
7)
僞編碼
1>指針/鼠標僞編碼
如果客戶端請求指針/鼠標僞編碼,那麼就是說它有能力進行本地繪製鼠標。這樣就可以明顯改善傳輸性能。服務器通過發送帶有僞鼠標編碼的僞矩形來設置鼠標的形狀作爲更新的一部分。僞矩形的x
和y表示鼠標的熱點,寬和高表示用像素來表示鼠標的寬和高。包含寬X高像素值的數據帶有位掩碼。位掩碼是由從左到右,從上到下的掃描線組成,而每一掃描線被填充爲floor((width
+7) / 8)。對應每一字節最重要的位表示最左邊像素,對應1
位表示相應指針的像素是正確的。
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
字節數 |
類型[
值 ] |
描述
-- - - - - - - - - - - - - - - - + - - - - - - - - - - - - - + - - - - - - -
寬x
高x
字節/PIXEL | PIXEL
數組 |
指針象素
floor((寬+ 7)=8) x
高 | U8
數組 |
位掩碼
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2>桌面大小僞編碼
如果客戶端請求桌面大小僞編碼,那麼就是說它能處理幀緩存寬/高的改變。服務器通過發送帶有桌面大小僞編碼的僞矩形作爲上一個矩形來完成一次更新。僞矩形的x
和y被忽略,而寬和高表示幀緩存新的寬和高。沒有其他的數據與僞矩形有關。
字節數 |
|
描述 |
1 |
U80 |
消息類型 |
1 |
填充 |
|
1 |
U16 |
矩形編號 |