前幾章討論了主從式模型、客戶端與伺服器的角色及其互動方式。本節深入客戶端的內部構造,伺服器則留待下一節。
網路化使用者介面#
客戶端機器的主要任務是提供使用者與遠端伺服器互動的手段,大致有兩種支援方式:
- 每個遠端服務各有一個本地對應程式:客戶端機器上為每個遠端服務準備一個能透過網路聯繫該服務的對應端。典型例子是 PDA 上的行事曆應用要與遠端(可能共享的)行事曆同步——由應用層協定處理同步。
- 只提供便利的使用者介面、直接存取遠端服務:客戶端機器實質上只是一台終端機,不需本地儲存,一切處理與儲存都在伺服器端完成,是與應用無關(application-neutral)的解法。這種**瘦客戶端(thin-client)**做法隨著網際網路連線普及、手持裝置日益精巧而愈受重視;如前一章所論,瘦客戶端也因簡化系統管理而受歡迎。

圖 3-8:(a) 具備自有協定的網路化應用程式;(b) 允許存取遠端應用程式的一般性解法
範例:X Window 系統#
X Window 系統(通常簡稱 X)大概是最古老且仍廣泛使用的網路化使用者介面之一,用來控制包含螢幕、鍵盤與滑鼠等指向裝置的點陣圖終端機。某種意義上,X 可視為作業系統中控制終端機的那一部分:
- 系統核心是 X kernel:包含所有終端機專屬的裝置驅動程式,因此高度依賴硬體。它提供相對低階的介面來控制螢幕、擷取鍵盤與滑鼠事件。
- 這個介面以名為 Xlib 的函式庫提供給應用程式。Xlib 可向 X kernel 送出建立或銷毀視窗、設定顏色、定義游標樣式等請求;X kernel 則對鍵盤滑鼠等本地事件送回事件封包。
- 有趣之處在於 X kernel 與 X 應用程式不必在同一台機器上:X 提供 X protocol 這個應用層通訊協定,讓 Xlib 實例與 X kernel 交換資料與事件。
- 多個應用程式可同時與 X kernel 溝通,其中一個具特殊權限的應用是視窗管理器(window manager):它決定顯示畫面的整體「外觀與感受」——視窗如何加上按鈕裝飾、如何擺放等,其他應用程式都得遵守這些規則。

圖 3-9:X Window 系統的基本組織
X 融入主從式運算的方式很值得玩味:X kernel 接收(可能來自遠端應用程式的)操作顯示器請求,因此 X kernel 是伺服器,應用程式反而是客戶端。這套術語被 X 正式採用,嚴格說來沒錯,卻很容易造成混淆。
瘦客戶端網路運算#
應用程式透過 X 的顯示指令操作畫面,這些指令通常經網路送達 X kernel 執行。X 應用理應把應用邏輯與使用者介面指令分離,可惜實務上常非如此:如 Lai 與 Nieh(2002)所報告,大量應用邏輯與使用者互動緊密耦合——應用程式會送出許多請求給 X kernel,而且每個都要等回應才能走下一步。這種同步行為在高延遲的廣域網路上會嚴重拖累效能。以下是幾種解法。
NX:重新設計 X protocol 的實作(Pinzari, 2003),重點在壓縮 X 訊息以減少頻寬:
- 訊息拆成固定部分(視為識別碼)與可變部分。多個訊息常有相同識別碼、且往往攜帶類似資料,因此可只傳送同識別碼訊息之間的差異。
- 收送雙方各維護一個以訊息識別碼查詢的本地快取。送出訊息前先查快取:命中就用差分編碼只送差異,接收端同樣查快取後靠差異解碼;未命中則用標準壓縮技術——光這樣通常就有四倍的頻寬改善。
- 整體而言此技術的頻寬縮減可達上千倍,讓 X 連 9600 kbps 的低頻寬鏈路都能跑。
- 重要副作用:快取讓收送雙方共享「目前顯示狀態」的資訊,例如應用程式查詢物件的幾何資訊只需查本地快取即可,光這點就減少了維持應用與顯示同步所需的訊息數。
傳送原始像素:即使有這些改進,X 仍需要在顯示端跑一個顯示伺服器——對手機這類簡單顯示裝置可能太苛求。一種讓顯示端軟體極簡的解法是把所有處理都放在應用程式端,連像素層級都由應用端控制,點陣圖的變化再經網路送到顯示端、直接寫入本地 frame buffer。
這種做法需要高明的壓縮技術,否則頻寬立刻成為問題。例如在 320 × 240 的螢幕(許多 PDA 的常見尺寸)上以每秒 30 幀顯示視訊、每像素 24 位元編碼,不壓縮就需要約 53 Mbps 的頻寬。而壓縮意味著接收端要解壓縮——沒有硬體支援時可能運算成本高昂;加硬體支援又推高裝置成本。另一個代價是:原始像素層級完全喪失應用語意,無從利用。
THINC:折衷的高階顯示指令(Baratto 等人,2005):
- 提供少量在視訊裝置驅動程式層級運作的高階顯示指令——與裝置相關、比原始像素操作強大、又比 X 這類協定簡單。顯示伺服器因此可以簡單得多(有利 CPU 用量),同時仍能利用應用相關的最佳化來減少頻寬與同步。
- 應用程式的顯示請求被攔截並轉譯成低階指令;藉由攔截,THINC 能利用應用語意決定最佳的低階指令組合。
- 轉譯後的指令不立即送出而是排入佇列:批次處理可把多個顯示指令彙整為一個,減少訊息數——例如新指令繪製的區域實質覆蓋了仍在佇列中的舊指令的效果時,舊指令就不必送了。
- 更新一律由應用端**推送(push)**而非等顯示端來要,省去顯示端發出更新請求的延遲。
- 整體效能比較上,THINC 表現較佳,但與 NX 大致在伯仲之間。
複合文件#
現代使用者介面能做的遠不只 X 這類系統:許多介面允許多個應用程式共享同一個圖形視窗、並透過使用者動作交換資料。
- 拖放(drag-and-drop):例如把檔案 A 的圖示拖到垃圾桶圖示上以刪除檔案——介面不只是排列圖示,還得在 A 的圖示移到垃圾桶上方時,把檔名傳給垃圾桶對應的應用程式。
- 就地編輯(in-place editing):例如一份含文字與圖形的文件在文書處理器中顯示,滑鼠移到圖片上時,介面把資訊交給繪圖程式讓使用者直接修改圖片;若使用者旋轉了圖片而影響排版,介面再把新的長寬回報給文書處理器自動更新版面。
這些介面背後的關鍵概念是複合文件(compound document):一組可能種類迥異(文字、圖片、試算表等)的文件,在使用者介面層被無縫整合。支援複合文件的介面隱藏「不同應用程式各自處理文件不同部分」的事實;當某一部分的變動影響其他部分時,介面會採取適當措施(例如通知相關應用程式)。與 X 的情況類似,複合文件相關的應用程式不必在客戶端機器上執行——但這類介面顯然要做多得多的處理。
用於分散透明性的客戶端軟體#
客戶端軟體不只有使用者介面:許多情況下,主從式應用的部分處理層與資料層也在客戶端執行。一個特殊類別是嵌入式客戶端軟體——ATM、收銀機、條碼讀取器、電視機上盒等,其使用者介面只占客戶端軟體的一小部分,本地處理與通訊設施反而是大宗。
除了介面與應用相關軟體,客戶端軟體還包含達成**分散透明性(distribution transparency)**的元件。理想上客戶端不該察覺自己在與遠端行程通訊;相較之下,基於效能與正確性的理由,分散對伺服器往往較不透明——例如第 6 章將提到,複製的伺服器有時需要彼此通訊,以確保操作在各副本上以特定順序執行。各種透明性在客戶端的處理方式:
- 存取透明性(access transparency):通常靠從伺服器介面定義產生客戶端 stub 來達成——stub 提供與伺服器相同的介面,同時隱藏機器架構差異與實際通訊。
- 位置/遷移/重新定位透明性:好的命名系統至關重要,且常需客戶端軟體配合。例如客戶端已繫結到伺服器時,可在伺服器換位置時直接得到通知,由客戶端中介軟體隱藏伺服器目前的地理位置、必要時透明地重新繫結——最糟情況也只是使用者察覺短暫的效能下降。
- 複製透明性(replication transparency):常以客戶端解法實現。例如把請求轉發給每一個副本,再由客戶端軟體透明地收齊所有回應、只回傳單一回應給客戶端應用。

圖 3-10:以客戶端解法達成伺服器的透明複製
- 失效透明性(failure transparency):遮蔽與伺服器的通訊失敗通常由客戶端中介軟體處理——例如設定成反覆嘗試連線,或幾次失敗後改試另一台伺服器;甚至有像網頁瀏覽器連不上伺服器時,改回傳前次會談快取資料的做法。
- 並行透明性:可透過特殊的中介伺服器(尤其是交易監視器)處理,對客戶端軟體的要求較少;持久透明性則常完全在伺服器端處理。