1. 程式人生 > >請移架http://blog.sina.com.cn/u/2765457197

請移架http://blog.sina.com.cn/u/2765457197

通過這篇文章,我完全解決了一個AS3 中使用Socket的安全問題.

按照這篇文章這樣子做,不用看其他的文章,就解決了,而且很簡單.

講一下我的目標和遇到的問題以及解決的路徑:

1、首先這是一個網站,通過點選一個按鈕,然後傳送命令到終端;(類似點對點的聊天)

2、然後我就做了一個類似私聊的功能,把這個功能的程式碼完全複製到我的專案裡面的時候,就出現了這個錯誤【錯誤資訊: Error #2044: 未處理的 SecurityErrorEvent:。 text=Error #2048: 安全沙箱衝突:http://web.a.com/online.swf 不能從 10.20.199.182:8000 載入資料】,於是就到網上找解決方案:

3、找到的解決方案都說有三種方式:843埠監聽、在客戶端程式碼中使用Security.loadPolicyFile("xmlsocket://22.20.192.149:1038");方法、還有一個我不記得了。然後我就試了第二種方法,就是在伺服器端放crossdomain.xml檔案(這個我在上一篇部落格有寫怎麼放),試了好久,在昨天終於不報上面的SecurityErrorEvent這個錯了,雖然不報錯了,但是都連線不上,於是又去找資料;

4、實在沒辦法,有Debug一下,發現報了一個新的錯【[SWF] /BrainpowerBlazeds/bin/BrainpowerBlazeds.swf - 1,309,421 bytes after decompression
警告: 等待 socket 策略檔案時在 xmlsocket://10.20.192.149:843 上超時(3 秒鐘)。這不會造成任何問題,但可訪問

http://www.adobe.com/go/strict_policy_files_cn 以獲得說明。】

5、根據這個錯,才找到以下的這篇我轉載過來的非常好的資料,才完全解決了。

總的來說:伺服器端(java端)的主調程式我新建了兩個ServerSocket:A和B。我用一個A監聽843埠,如果發來<policy-file-request/>,我就呼叫一個執行緒Server843Thread(自定義的類)把策略檔案(String)傳送回去,接著把這個A關掉。這時候B還是開啟的,所以當客戶端發來<doopen-file-request/>(這個是客戶端發來的我自定義的一個字串),伺服器判斷髮來的是<doopen-file-request/>而不是<policy-file-request/>,就呼叫另外一個執行緒ChatThread(專門處理髮送過來的我自定義的資訊的執行緒),就ok了。

注意:客戶端連線服務端的時候不用管843埠,這是Adobe設定專門用來發送和接受安全策略檔案的埠(據說Adobe準備申請該埠為專屬埠),只要連線上面說的ServerSocket B中指定的埠即可(也就是除了843的另外一個,這裡用的是9999埠),廢話好多(希望能提供多一些說明讓大家看懂),其實客戶端連服務端的程式碼就是這樣:socket.connect("localhost",9999);

說明一下:這是通過監聽843埠傳送安全策略檔案(crossdomain.xml),用自定義埠9999進行自定義內容通訊的例子。

解決AS3 Socket程式設計中最令人頭疼的問題

--解決AS3 Socket安全問題

什麼是最令人頭疼的問題?也許大家會異口同聲的說:“安全問題”,不錯,不僅僅是AS3 的Socket,整個AS3語言中最令人頭疼的問題也無非就是安全問題了。

很 多同行的兄弟在鬱悶的時候就會罵Adobe。但是,罵歸罵,問題終歸是要解決的,Adobe做這樣的限制肯定是有他的用意的,大家都知道,swf檔案是很 容易被反編的,那麼也就是說你的swf檔案內部與伺服器通訊的方式及路徑是很容易被別人發現的,如果你的伺服器中沒有任何訪問限制,那麼你的伺服器很容易 被一些人攻破,這並不需要很高的水平,只要一直刷,你的伺服器就完了。

兄弟,您罵夠了嗎?我們來解決問題吧?

用Java寫完Socket伺服器後,執行,一切正常,用Flex寫全Socket客戶端後,執行,一切正常,可是當把生成的swf檔案拷到其它地方來執行就出錯了,總是無法連線伺服器,然後就開始拋securityError,下面我們看一下輸出資訊。

打 開Flash CS3,開啟遠端偵錯程式,選擇選單如 Debug->Begin Remote Debug Session->ActionScript3.0(中文版選擇選單如:除錯->開始 遠端除錯會話->ActionScript3.0),下面我們開啟客戶端swf檔案(記得此檔案一定是除錯版swf),則它會自動連線Flash CS3 的偵錯程式,在Flash CS3中輸出相關的除錯資訊。

可以看到輸出資訊如下:

------------------------------------

[SWF] C:/Users/Administrator/Desktop/MyClientFlash.swf - 1112717 bytes after decompression

警告: [strict] 將忽略 xmlsocket://localhost:9999 處的策略檔案,因為出現語法錯誤。請訪問 http://www.adobe.com/go/strict_policy_files_cn 以解決此問題。

*** 安全沙箱衝突 ***

到 localhost:9999 的連線已停止 - 不允許從 file:///C|/Users/Administrator/Desktop/MyClientFlash.swf 進行連線

錯誤: 拒絕請求位於 xmlsocket://localhost:9999 的資源(請求者從 file:///C|/Users/Administrator/Desktop/MyClientFlash.swf 發出請求),原因是缺乏策略檔案許可權。

------------------------------------

原因是沒有在伺服器的9999埠放置安全策略檔案(我寫的伺服器用的是9999埠),那麼好吧,我就在此處給客戶端返回了一個安全策略檔案資訊,此檔案格式如下:

<?xml version="1.0"?>

<cross-domain-policy>

    <site-control permitted-cross-domain-policies="all"/>

    <allow-access-from domain="localhost" to-ports="9999,300-400" />

</cross-domain-policy>

上述示例中是允許來自localhost域的swf檔案訪問9999埠和300至400埠,你也可以用*來代替localhost以允許來自任何域的swf檔案訪問。

此時我將客戶端檔案請求的資訊在Java中打印出來,看到的是一段包含<policy-file-request/>的字串,當Java伺服器接收到這個字串時,立即返回安全策略檔案字串。

我想這樣應該沒什麼問題了吧,可是當我再連線伺服器時仍然無法連線,輸出資訊成了這樣:

-------------------------------------

[SWF] C:/Users/Administrator/Desktop/MyClientFlash.swf - 1112717 bytes after decompression

警告: 等待 socket 策略檔案時在 xmlsocket://localhost:9999 上超時(3 秒鐘)。這不會造成任何問題,但可訪問 http://www.adobe.com/go/strict_policy_files_cn 以獲得說明。

*** 安全沙箱衝突 ***

到 localhost:9999 的連線已停止 - 不允許從 file:///C|/Users/Administrator/Desktop/MyClientFlash.swf 進行連線

錯誤: 拒絕請求位於 xmlsocket://localhost:9999 的資源(請求者從 file:///C|/Users/Administrator/Desktop/MyClientFlash.swf 發出請求),原因是缺乏策略檔案許可權。

-------------------------------------

這時我並不灰心,就按照它的說明去了http://www.adobe.com/go/strict_policy_files_cn這裡檢視說明了。

等我看到這個頁面時,我真的鬱悶了,上面全是亂說一通,根本不著邊,全是一些沒用的資訊,虧Adobe想得出來提示我到這裡看。

就 在我將要放棄解決這個問題的時候,我發現了另外一個現象,那就是當我剛開始連線伺服器時,伺服器端並沒有打印出來客戶端的請求資訊 (<policy-file-request/>),而是在Flash CS3的偵錯程式輸出了超時錯誤之後,伺服器端才打印出來這個請求信 息。

這時我看到了一線希望,那就是伺服器端確實出現了等待,這肯定是伺服器端的程式問題。伺服器端接收請求的處理程式碼片斷如下:

BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));

if(br.readLine().indexOf("<policy-file-request/>")!=-1){

//開始返回授權檔案資訊

...

}

其中變數s是ServerSocket例項通過accept方法獲得的Socket例項。

此時我開始懷疑是readLine方法的問題了,因為readLine方法是當程式讀到/n或者/r時才會返回資訊,所以肯定是此方法中出現了等待,因為起初客戶端並沒有傳來換行符或者回車符。

於是我改變了讀取字串的方法,不再用readLine了,而取流中前22個字元,程式碼片斷如下所示:

BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));

char[] ch=new char[22];

br.read(ch, 0, ch.length);

StringBuffer sb=new StringBuffer();

for(int i=0;i< ch.length;i++){

sb.append(ch[i]);

}

String st=sb.toString();

if(st.indexOf("<policy-file-request/>")!=-1){

//開始返回授權檔案資訊

...

}

當我再連線伺服器時,果然不出我所料,成功連線伺服器。

但是連線過程有點慢,貌似此過程也正好是3秒鐘,莫非在連線此伺服器之前已經進行了另外一次連線,而且是失敗的。

檢視Adobe官網的資料才明白,flashplayer會在連線指定的埠之前連線目標主機的843埠,如果3秒後得不到授權檔案才再向指定的埠去請求授權檔案,如果再經過3秒還得不到授權檔案的話,則斷開連線,丟擲securityError。

那 意思就是說在連線我的伺服器的9999埠之前還連線了我的伺服器的843埠,並且在843埠等待了3秒,沒有得到授權檔案,之後開始向我指定的埠 請求此授權檔案。那好吧,既然你要了,我就給你吧,不給你的話你還再磨磯磨磯,於是我又在843埠開了一個ServerSocket,此處專門處理授權 檔案的請求。

這時我再連線伺服器,呵呵,特快專列(T843),立即就連線上了。

說明:貌似有很多客戶機上的843端被禁用了,所以為了保險,需要在指定埠和843端都要能夠處理授權檔案的請求。

以下是示例程式及原始檔下載: