第四章 系統設計與實作
4.3 客戶端之系統設計
4.3.1 客戶端架構
客戶端負責作為本地端與伺服器端溝通的橋樑,需要具備的能力有:本地端聯絡人 資料庫的存取、伺服器端聯絡人資料庫的存取、即時通訊上線狀態的感知、來自伺服端 URI 命令的處理,以及呼叫 URI 所指定的客戶端即時通訊程式的能力。
在聯絡人資料的方面,本系統目前實作的目標是 Windows 作業系統所內建之 Windows Address Book(WAB,中文版 Windows 系統稱為「通訊錄」)。而我們希望未來 能夠方便擴充支援其他的聯絡人資料庫系統,所以我們將聯絡人資料存取所需的動作,
抽取出來形成一抽象層 Contact Management,而伺服器端的聯絡人資料庫存取與本地端 的資料庫存取動作類似,也納入此架構之下。在實作中我們繼承此一介面,實作了 WAB 以及 Server 端聯絡人的存取。
在聯絡人上線狀態的感知方面,系統目前實作支援的有 MSN Messenger 以及 Skype。同樣地,為了未來的擴充考量,也設計一個抽象介面。在此介面下實作 MSN Messenger 以及 Skype 的狀態感知功能。
在即時通訊程式的控制方面,雖然實作中只有 MSN Messenger 需要由我們的客戶端 來控制,但也實作了抽象介面 IM Controlling,以滿足未來支援其他的即時通訊程式之 需求。
再加上URI的處理,客戶端用一個Application Controller來控制協調上述模組間的協 同運作,再提供使用者介面讓使用者控制程式之行為。形成客戶端之系統架構,如圖 11。
User Interface
Application Controller
(Abstract) Contact Management
(Abstract) Presence Checking
(Abstract) IM Controlling
URI Handling WAB
Access
Server Address
Book Access
MSN Messenger
Presence
Skype Presence
MSN Messenger
Controller
圖11 客戶端架構圖
4.3.2 與即時通訊系統之互動
客戶端程式與即時通訊系統之互動,有兩種情形:獲取某個聯絡人的上線狀態,以 及呼叫某個即時通訊系統之客戶端程式。在實作裡我們支援了兩種即時通訊系統,MSN Messenger 以及 Skype。
MSN Messenger 提供了官方的 API,稱為 Messenger Type Library,MTL 為微軟之 Windows Messaging Service 提供之 COM 介面,Windows 內建的 Windows Messenger,
以及 MSN 的 MSN Messenger 都是使用同樣的核心,在使用 COM 函式庫的時候,只要 選 擇 具 現 (instance) 不 同 的 介 面 , 就 可 以 控 制 不 同 的 程 式 (IMessenger: Windows Messenger、IMessenger3: MSN Messenger)。Skype 也同樣使用了 COM 介面來提供外部 程式存取 Skype 客戶端程式的 API,稱為 Skype4Com。我們的客戶端程式使用這兩個 API 來實作對於即時通訊程式的互動功能。
在上線狀態方面,我們的抽象介面稱為IMChecker(請參考
)。此介面提供了一個方法,稱為 getStatus(),傳入要獲取的聯絡人即時通訊帳號,
此方法會回傳該聯絡人之狀態,狀態型別為 IMStatus。而各種可能的狀態,則由繼承此 介面之類別,視其所實作之即時通訊系統來自行定義。我們包裝 MSN Messenger 以及 Skype API 之底層動作,實作的兩個類別稱為 MSNChecker 以及 SkypeChecker。
表7 IMChecker介面之方法列表
Name Parameters Retuen Description
getSTatus user: String IMStatus 取得即時通訊代號為 user 之 聯絡人上線狀態IMStatus
在即時通訊程式的呼叫方面,我們的抽象介面稱為 IMController(請參考錯誤! 找 不到參照來源。),提供的方法有 openText()、openVoice()、openVideo()與 openPhone(),
呼叫時傳入通訊目標之帳號,即可建立對應之對話連線。實作的類別為 MSNController,
Application Controller 收到瀏覽器傳來之 URI,可使用 MSNController 類別打開 MSN Messenger 指定類型的交談視窗。
表8 IMController 介面之方法列表
Name Parameters Retuen Description
openText target: String - 與即時通訊代號為 target 之 openVideo target: String -
撥出 target 之聯絡人電話號 openPhone target: String - 碼
4.3.3 伺服器端與本地端聯絡人資料庫之存取
聯絡人資料庫之存取,我們的抽象介面稱為 ContactManager(請參考錯誤! 找不到 參照來源。)。
表9 ContactManager 介面之方法列表
Name Parameter Return Description
clear - - 清除目前聯絡人資
料庫中所有資料
getAllContacts - contactList:
ContactList
取回目前聯絡人資 料庫中所有聯絡人
addContact contact:
Contact - 將聯絡人contact 加入聯絡人資料庫
contact:
Contact -
將聯絡人contact 自聯絡人資料庫刪 除
delContact
modifyContact
contact:
oldContact contact:
newContact -
修改資料庫中已存 在之聯絡人
oldContact 資料 為newContact getAllGroups - groupList:
GroupList
取回目前聯絡人資
modifyGroup
group:
oldGroup group:
newGroup
-
修改資料庫中已存 在之群組
oldGroup 資料為 newGroup
Name Parameter Return Description
addEntryToGroup
contact:
Contact
parentGroup:
Group
-
將聯絡人contact 加入群組
parentGroup 為 群組元素
addEntryToGroup
續下頁 承上頁
group: Group parentGroup:
Group -
將聯絡人contact 自群組
parentGroup 中 刪除
deleteEntryFromGroup
contact:
Contact
parentGroup:
Group
-
將群組group 加入 群組
parentGroup 為 群組元素
group: Group parentGroup:
Group -
將群組group 自群 組parentGroup 中刪除
deleteEntryFromGroup
getTime - time:
Timestamp
取得目前聯絡人資 料庫之時間
4.3.3.1 客戶端聯絡人資料庫
本地端聯絡人資料庫,支援的系統為Windows內建之Windows Address Book(WAB, wab.exe, 圖 6)。Windows Address Book提供一API稱為WAB API,可供第三方程式存取 WAB之聯絡人資料庫。微軟本身亦利用這個API讓該公司旗下產品Outlook以及Outlook Express可使用WAB作為電子郵件通訊錄。此程式支援兩種聯絡人管理方案:資料夾以 及群組。但資料夾屬於該程式自己的實作,並非API所提供的功能,也無法透過API來存 取到資料夾結構,故在實作中我們利用其群組功能來讓客戶端與伺服器端之聯絡人管理 結構同步。繼承ContactManager,包裝WAB API所實作之類別稱為WABContactManager。
在4.2.2提到,系統利用CID來作為在客戶端與伺服端間,識別一個聯絡人的方法。
但是在客戶端要怎麼讓聯絡人與CID對應呢?WAB API提供了一個機制稱為Named Properties,可以讓第三方自訂WAB中聯絡人的屬性。我們的客戶端程式即利用Named Properties機制來將CID設定為聯絡人的屬性,即可將CID與聯絡人一一對應。
但是在本地端 WAB 程式裡,新增的聯絡人並不具此屬性。所以在取得本地端之聯 絡人列表時,WABContactManager 若發現一個聯絡人不具此屬性,會自動產生一個 CID,但與伺服器端不同的是,WABContactManager 端產生之 CID,開頭是'CC',以避 免在伺服器端與客戶端間發生 CID 重複的情形。另外,在本地端產生之 CID,其產生的 CID 包括本地端獨一無二的 MAC Address,以避免同一位使用者在不同電腦使用多個客 戶端,可能產生出相同 CID 的情形。同樣地,GID 也是透過類似的機制產生,其開頭為 'GC'。
4.3.3.2 伺服器端聯絡人資料庫
同樣地,我們也將4.2.4所描述之伺服器端API,以及相關的HTTP網路通訊,包裝為 伺服器端之聯絡人管理類別,ServerContactManager。不同於WABContactManager的地方 是,伺服器端有聯絡人上線狀態之屬性,所以ServerContactManager額外實作了關於聯絡 人上線資訊之方法。
4.3.4 聯絡人資料庫同步
每隔一段時間,客戶端程式會取得本地端以及伺服器端之聯絡人列表,並進行同步 演算,更新兩端之聯絡人資料庫。
Application Controller 紀錄兩個時間戳記,,分別記錄上次同步後,伺服器端與客 戶端的時間。兩邊的時間可能有誤差,故在比較兩邊項目何者較新的時候,會將此誤差 計算進去。
首先Application Controller透過ServerContactManager取得伺服器端之聯絡人列表,
以及群組列表。再透過WABContactManager取得本地端之聯絡人列表,以及群組列表,
如果是本地端新增的聯絡人或群組,CID/GID會以4.3.3.1描述之機制產生。
接著 Application Controller 會依據下列原則比對兩份聯絡人列表:
z 發現某 CID 同時存在於兩邊的列表:
比對兩邊的 LAST_MODIFICATION_TIME,可能有兩種情況:
伺 服 器 端 的 LAST_MODIFICATION_TIME 較 新 , 且 伺 服 器 端 LAST_MODIFICATION_TIME 大於 SERVER_LAST_SYNC_TIME:
表示在上次更新以後,此項目在伺服器端有被修改過,用伺服器端資料更 新本地端資料
本 地 端 的 LAST_MODIFICATION_TIME 較 新 , 且 本 地 端 LAST_MODIFICATION_TIME 大於 LOCAL_LAST_SYNC_TIME:
表示在上次更新以後,此項目在本地端有被修改過,用本地端資料更新伺 服器端資料
z 發現一 CID 只存在於伺服器端的列表:
比對這個項目的 LAST_MODIFICATION_TIME,可能有兩種情況::
伺 服 器 端 LAST_MODIFICATION_TIME 大 於 SERVER_LAST_SYNC_TIME:
表示在上次更新以後,在伺服器端被新增的項目,將此項目加到本地端
伺 服 器 端 LAST_MODIFICATION_TIME 小 於 SERVER_LAST_SYNC_TIME:
伺服器端此項目在上次更新以後並未被更動,表示是本地端已刪除的項 目,從伺服器端刪除該項目
z 發現一 CID 只存在於本地端的列表:
比對這個項目的 LAST_MODIFICATION_TIME,可能有兩種情況::
本地端 LAST_MODIFICATION_TIME 大於 LOCAL_LAST_SYNC_TIME:
表示在上次更新以後,在本地端被新增的項目,將此項目加到伺服器端
本地端 LAST_MODIFICATION_TIME 小於 LOCAL_LAST_SYNC_TIME:
本地端此項目在上次更新以後並未被更動,表示是伺服器端已刪除的項 目,從本地端刪除該項目
更新完聯絡人列表後,Application Controller 依據上述同樣的原則來更新群組列表,
但在修改群組資料時,除修改群組名稱外,會一併修改群組內含哪些元素的資訊。然而 因為 WAB API 只能知道該群組上次何時被存取,而無法知道某個群組元素何時被加入,
故更新群組時,會讓較新一方的群組元素完全取代較舊一方的群組元素。
做完上述之同步動作後,客戶端程式再取得伺服器端以及本地器端之時間,並分別 儲存至 SERVER_LAST_SYNC_TIME 以及 LOCAL_LAST_SYNC_TIME 兩個時間戳記。
4.3.5 瀏覽器呼叫伺服器端 API 的方式
在 4.2.4 所 描 述 之 伺 服 器 端 API 也 可 讓 瀏 覽 器 直 接 呼 叫 , 在 實 作 上 我 們 使 用 AJAX(Asynchronous Javascript And XML)技術來作為瀏覽器呼叫伺服器端API之方式。
在傳統的互動式網頁裡,瀏覽器透過 POST/GET 傳送變數給伺服器,或從伺服器讀 回新的資料時,需要重新載入整個頁面,來獲取由伺服器端產生的,新的頁面。而 AJAX 則是利用 Javascript 類別 XMLHttpRequest,在背景悄悄地與伺服器端通訊,並且可以將 傳回的資料用 XML DOM(Document Object Model)解析。再利用 DOM 來動態地修改局 部網頁的內容。如此一來不必重新載入整個頁面即可獲取最新的資訊,伺服器端也不用 重新產生整個網頁。使用者可獲得較佳的使用體驗,伺服器端的負擔也較小。
考量到以上的優點,本系統選擇在網頁介面中使用 AJAX 介面作為呼叫伺服器端 API 之媒介。伺服器端傳回的 XML 格式回應,可方便地使用 DOM 解析,並動態更新 網頁上的資訊。
4.3.6 系統元件互動實例
以下以幾個實例來說明客戶端之各個模組間互動方式。
4.3.6.1 聯絡人狀態同步
當客戶端透過 api_login 登入伺服器端後,會從伺服器端取得聯絡人列表。再利用
當客戶端透過 api_login 登入伺服器端後,會從伺服器端取得聯絡人列表。再利用