通訊機制與流程圖
 
如何讓網頁客戶之間通訊?

要製作網頁版的線上遊戲,關鍵機制是如何讓開啟網頁的兩個客戶彼此通訊?我們在「網頁即時通」那個單元介紹的是使用ASP.NET伺服端的AJAX擴充元件設計的連線網頁。雖然我們知道所謂的AJAX機制,最終客戶端是以JavaScript程式與伺服端通訊,但我們並不需要直接寫這些程式,而是由網頁伺服器配合.NET程式庫所自動產生的。

在此我們將更精準的分別設計客戶端的HTML網頁與伺服端的ASPX程式。讓應用程式的介面與通訊功能互相獨立,這樣就可以用一般網頁加上 JavaScript 程式設計網頁遊戲或應用程式的客戶端,不必完全依賴一體成形的ASPX檔案。須知使用ASPX,我們要設計各種操作介面時,很難完全自行掌控那些程式或介面要由伺服端?哪些由客戶端處理?最終會導致伺服端負擔過重,有違線上遊戲系統的運作的基本要求,就是減輕伺服端負荷。

在客戶端我們將以 JavaScript 程式實作AJAX與伺服端通訊的程式,各位會發現與前面學的UDP或TCP程式架構非常相似,會有一個監聽物件持續監聽遠(伺服)端訊息,要對外發言時會臨時使用另一個通訊物件送訊息。當然因為不同客戶之間還不能以網頁互相定位,訊息仍必須經過網站,就是伺服器轉傳,不能像UDP一樣在客戶之間直接傳送,因此伺服端還是必須有一個ASPX程式負責作為訊息轉送中心,但它可以完全沒有網頁介面,只做通訊的功能。

網頁頁面設計
請開啟一個ASP.NET網站,加入一個HTML網頁,置入如下物件:

1. 左上方「遠端訊息」是一個 div標籤,id='Who',稍後用於顯示遠端誰傳來訊息。
2.「我是」(直接打字)的右方用於輸入自己的名稱,「想跟」的右方輸入交談對象的名稱,「講說」的右方輸入發言。
3.確定按鍵的功能類似登入,輸入名稱且確定後就可以連線到伺服端領取自己的訊息
4.送出按鍵就是將訊息傳到伺服器,當然必須是寄件人、收件人與發言內容都寫好送出才會有意義。
5.由上而下四個文字方塊Input(Text)名稱依序是 Msg, Me, YouTalk,按鍵由上而下是Button1與Button2。

通訊物件設定的程式碼
要用HTML網頁與伺服端通訊,必須使用JavaScript的通訊物件,而且應該使用兩個物件,一個用於定時輪詢伺服端有無別人傳給自己的訊息,一個用於自己傳出訊息到伺服器(S),再請伺服器幫我們轉傳給目標客戶,也就是通話對象。受限於HTTP通訊的 Request-Response(要求與回應)架構,即使是我們想從伺服器傳訊息給客戶,也必須經過客戶的要求。所以取得別人訊息的過程其實是每個客戶定時去看信箱!只是不需要使用者自行操作(類似按重新整理的按鍵)而已。當然下面的init必須在網頁仔入時執行。

所謂的 R.onreadystatechange就是監聽有回應時的狀況,此時應該啟動一個 showInfo副程序,程式馬如下:

上述程式碼是當確定回訊正常時,將資料切割為寄件者與訊息內容,寄件者顯示於Who那個 div物件,訊息則顯示於Msg的文字方塊內。最後再稍等200毫秒,執行  req 程序,就是再度發出詢問訊息。

身分登入與啟動監聽的程式
在啟動監聽訊息之前必須讓伺服端知道你的身分,否則伺服端不會知道哪些訊息該回傳給你,就等同於一般網站的登入機制,在此只是在 Me 那個文字方塊輸入名稱,並以Button1事件確定,目的只是啟動 req程序,此程序必須先知道自己的名稱,否則與伺服器聯繫毫無意義。

我們讓登入後的Me物件有背景色的變化,提示客戶已經具有身分,可以接收伺服端訊息了!
接著是啟動監聽的 req 程式,此副程序首先建立一個”?/”+Me.Value的訊息內容,在我們的自訂協定中就是詢問有無給我Me的訊息?接著是將此訊息做「逸出字元」編碼(URI)。這是因為我們傳送的訊息中可能會有非英數字的內容(中文),我們又必須讓訊息附加於網址之後,以查詢字串的方式送回伺服端,此時任何訊息都必須符合 http 的 url 編碼方式,所以這是一個必要的程序。
    接著是指定回傳伺服器的服務網頁,我們在此還使用了一個隨機亂數,原因是多數瀏覽器預設如果要求通訊的網址與之前通訊網址完全相同時,會使用之前通訊的結果,而不實質連結伺服器取得新資料,這會讓更新無法持續。此地的亂數是刻意讓網址產生變化,迫使程式每次都必須實質聯繫伺服端取得新的資訊。
    如前所述,一旦 req 程式啟動了 R 對伺服端的詢問,不論有無新訊息,動作完成200毫秒之後又會繼續執行下一次的req詢問,就此建立了持續監聽伺服端是否有訊息傳來的機制。

發送訊息的程式
相對於監聽程式,發訊息時不需處理接聽,程式相對簡單,完整程式碼如下:

主要的發訊副程序 send的三個參數分別是:寄件人、收件人與訊息內容,我們會將三者以斜線分隔作為原始訊息。接著一樣經過 url編碼,因為前面已經建立接收伺服端訊息的程式,此地當然就不必寫回呼函數了。伺服端也會知道:我是誰?傳話給誰?和傳話的內容。

伺服端轉傳訊息的程式
在此我們是使用ASP.NET架構的VB程式語言撰寫伺服端程式,開啟一個aspx格式的網頁之後,我們只須在Page_Load事件中寫程式如下:

    首先是取得網址之後夾帶的變數內容,也就是客戶傳來的訊息m。如果不是空字串就必須處理,將訊息以斜線字元切開為幾個欄位資料。如前所述,如果第一個欄位是個問號,表示是來查詢有無信件的!就看看在網站公用變數中,是否有以此使用者為名的變數?有的話就回傳給該客戶,並將該網站公用變數清除。
    相對的,如果第一欄位不是問號表示是客戶主動發出的訊息,切開欄位後內容應該依序是寄件者、收件者與訊息內容。我們就以收件者為名,建立一個網站公用變數,內容是寄件者與訊息內容。當該收件者來定期查詢時,就可以將此變數內容回傳給他,他就會知道誰想跟他說甚麼了。至此,我們的通訊程式建立完畢,執行此網頁即時通的畫面概略如下:
 

為什麼不用ASPX?
此單元範例功能與使用ASPX檔案直接設計的網頁即時通幾乎完全一樣,但是被切割為客戶端的HTML,與伺服(網站)端的ASPX兩個檔案,客戶端也必須自己建立AJAX通訊程式,看起來更為複雜,那為何不用ASPX直接製作就好呢?
跨入App的關鍵!
主要原因是目前平板電腦與智慧型手機盛行,原有的Web-based網頁程式系統的客戶端紛紛被要求須製作App版本,目前要製作App除了使用對應智慧裝置作業系統的專用程式語言,如Java或Object-C之外,這些作業系統也都允許以HTML+JavaScript 語言為基礎設計App。這類「程式」雖有類似視窗程式的外觀,但其實是以網頁原始碼為其程式內容。
因此,如果我們系統的客戶端可以改寫為純粹的網頁格式(HTML檔案),等於已經製作完成App客戶端程式,就無須以另一種程式語言改寫客戶端程式了!
伺服端還是要的!
當然必須注意到伺服端的「服務」還是不可或缺的!所以ASPX檔案還是必須存在,除了提供轉傳客戶間的通訊,其實也可以包含資料庫存取或較複雜的資料處理等服務。只是我們不能再過度仰賴ASP.NET等伺服端技術,一次就做好伺服與客戶兩端的程式與頁面設計。不過這是Web-based程式要跨入智慧裝置與App程式領域必要的功夫!
只要想到:會了這招就可以自由地用JavaScript寫任何App連線遊戲,應該是非常值得的!