原文:http://blog.csdn.net/SCUM/archive/2008/10/21/3118175.aspx
1、前言
本文以標準兩層 C/S 架構為例,對 XMLSocket 通訊編程作一沉痛總結。
從開始到調試正常耗掉了我幾乎一周的時間,故為沉痛!尚東!!真是太尚東了!!!
為方便描述,把 Flash Player 稱作用戶端(Client),包括獨立的 Player 和嵌入瀏覽器的 Player。
2、用途
XMLSocket 類提供以 TCP/IP 方式進行程式間通訊的功能。
3、開發基本流程
流程無所謂,先做服務端也好,先做用戶端也罷,都不可能把一邊做完再做另一邊,總之是要同步進行,除非服務端已經存在。
4、用戶端開發
XMLSocket 類使用比較簡單,基本上就是幾個步驟:
1) 建立 XMLSocket 類的執行個體。
2) 寫好需要響應的事件代碼,事件很少,如下:
onConnect: Socket 成功串連後觸發,傳入一個參數,指定串連狀態
onClose: 伺服器端斷開 Socket 後觸發
onData: 收到服務端資料,或傳輸錯誤時觸發,傳入一個參數,為 undefined 時表示傳輸錯誤,否則為收到的資料
onXML: 收到服務端 XML 內容,或傳輸錯誤時觸發,參數同 onData
典型的程式碼片段如下:
...
var g_Socket = new XMLSocket();
g_Socket.onConnect = ge_OnConnect;
g_Socket.onClose = ge_OnDisconnect;
g_Socket.onData = ge_OnData;
...
3) 通過調用 connect( 服務端地址或IP, 服務連接埠 ) 方法發起串連請求。
4) 串連若成功,資料的收發處理就由自己決定了。
5、服務端開發
服務端根據情況可選各種語言開發,如 Java/C++/C#,只要能處理 Socket 的就行。
個人感覺,開發前期可用 C++/單線程,輸出和調試都方便,等通訊層穩定後,可考慮用 Java 實現管理邏輯,線上程安全、記憶體回收、鎖等方面,Java 都比 C++ 來得方便。
根據應用的不同,服務端的具體實現千變萬化,但基本的工作原理和內容是類似的:
1) 初始化內部資料
2) 開始監聽連接埠
3) 處理串連請求
4) 管理會話(Session)
5) 管理線程
6) 收集和分發資料
7) 實現商務邏輯
再展開來還有網路連接池、資料連線池、線程池、互動鎖等。
6、沙箱和安全性原則問題
此問題發生在串連時,準確地說是串連前,分別兩種情況:
6.1.1、本地播放
本地播放時,預設情況下 Flash Player 將不允許 swf 訪問任何網路。
訪問 http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html,將 swf 加入到許可列表,即可釋放保留。
6.1.2、WEB 發布
發布在 WEB 上的 swf, 將可能面臨跨域的問題。
Flash 中的通訊方式有兩種:
1) HTTP 方式:如 URLLoader 等用於載入遠程 swf、檔案、映像、音視頻流。
2) Socket 主要:如 XMLSocket,用於與遠程服務端建立長效串連。
Flash Player 6 以上版本引入了安全性原則檔案,在進行正式的通訊前,會檢查目標位置是否存在合法的安全性原則,以防止不同域內的應用無限制任意互訪。
HTTP 方式下,Flash Player 會檢查目標域根目錄下是否存在 crossdomain.xml,如果有,則擷取並分析其內容(內容後述)以確定是否允許繼續訪問。
Socket 方式下,Flash Player 擷取安全性原則稍微複雜些,從 9.0.115.0 版起,標準步驟如下(以下描述以 IE 為標準,例外情況後述):
1) 首先向目標主機 843 連接埠發起串連,並發送一個字串,內容為 "<policy-file-request/>",並等待返回安全性原則檔案並分析。
2) 若 1) 失敗,則檢查 AS 代碼中是否使用了 Security.loadPolicyFile( "xmlsocket://主機:連接埠" ) 方法載入安全性原則檔案,若有,則擷取並分析。
3) 若 2) 失敗,則向 AS 代碼中即將串連的 "目標主機:連接埠" 發起請求,過程同 1)。
4) 若成功獲得安全性原則檔案並經分析認為允許建立串連,則繼續執行 Connect() 方法,此時方真正嘗試建立與目標主機的串連。
6.1.3、解決方案
瞭解了上面說到的問題,解決方案便呼之欲出了,HTTP 串連方式不用再說,只說說 Socket 方式。
1) 在服務端寫一個程式,監聽 843 連接埠,當收到 "<policy-file-request/>" 時將恰當的策略內容(crossdomain.xml)發送回用戶端。
2) 在 AS 中通過 loadPolicyFile() 載入策略檔案,此處需注意使用 xmlsocket:// 而不是 http://。
3) 在標準服務連接埠中,檢測到 "<policy-file-request/>" 時,返回策略內容。
6.1.4、例外情況及測試結果
經測試發現,在 IE, Opera 中,Flash Player 會嚴格按上述步驟檢查安全性原則。
在 FireFox, Chrome 中發起串連時,Flash Player 並不會向服務端發送 "<policy-file-request/>",而是直接連接成功。這應該是 Flash Player 不同實現版本的原因。
7、資料轉送中的問題
在 XMLSocket 資料轉送中,需要注意以下細節,否則會出來些莫名其妙的問題。
7.1、結束符號
XMLSocket 接收到服務端下發的資料時,將連續放於接收緩衝區,直到接收到 "/0" 位元組(位元組內容為 ASCII 值 0),才認為接收完成,並調用相應的 onData 或 onXML 事件。
服務端若用 Java 編寫,並使用標準的 String 類族,則在發送資料結尾應手動加上 "/0"。
若用 C++ 編寫,由於 C++ 中標準字串類型便是以位元組 0 作結束標記,故不必再加 "/0"。
* C++ 中需注意另一個問題,若自行進行了字串處理,在決定字串長度時,標準的 strlen 及 String.Length() 等返回的均是實際有效字元個數,最終向網路發送時,總長度應加 1 位元組,以容納結尾的位元組 0。
* 此問題在發送安全性原則內容時同樣存在,故需重視。
7.2、中文問題
預設情況下,不管從哪一端發向另一端的資料,若包含了中文字元,都會產生亂碼的現象,解決方案有二:
1) 在 AS 中加入 "System.useCodepage = true;" 強制使用本地代碼集,此法最方便,但是在跨語種平台上仍會出現亂碼。
2) 在代碼中自行編寫轉碼函數,此法複雜些,但通用性強。具體轉碼演算法網上很多,主要是 C++ 服務端需要,Java 中使用 JDK 類轉換為 UTF-8 即可。