一、問題描述
將flash發佈爲html格式後,加載頁面後,swf沒法與服務器進行socket通訊。Flash端顯示的錯誤爲:
securityErrorHandler信息: [SecurityErrorEvent type="securityError" bubbles=false cancelable=false eventPhase=2 text="Error #2048"]
在服務器端顯示的信息是由客戶端嘗試進行鏈接,可是沒法接受數據。接受的數據顯示爲空。
2.問題緣由:
最新的Flash player 9.0.124.0,當flash文件要進行socket通訊的時候,須要向服務器端獲取crossdomain.xml文件。若是找不到就出現客戶端沒法鏈接服務器的現象。
瞭解flash發起socket通訊的三個過程
當封裝在頁面的flash發起socket通訊請求的時候會先尋找服務器端的843端口,獲取Crossdomain.xml文件,當服務器沒有開啓843的時候,flashPlayer會檢查發起請求的swf文件中中有沒有使用Security.loadPolicyFile來加載策略文件Crossdomain.xml,若是仍是沒有就會看這個發起請求的swf要鏈接的目標端口有沒有策略文件。若是都沒有那麼鏈接失敗,返回如上的出錯提示。
爲何老版本的Flash player沒有這個問題?
從一些官方的一些資料中瞭解了一下。之前的Flash Player不管你採用urlRequest的http請求方式或者xmlsocket socket方式,他們都共用一個安全策略文件。這個策略文件只要你放在主域的目錄下就好了。而如今不行了,如今的策略文件若是你使用http請求方式那麼須要把策略文件放在目錄下面,若是你使用socket請求方式就必須經過socket端口來接收這個策略文件。
對應調用的方式爲:
http請求——》Security.loadPolicyFile(「http://www.xxx.com/crossdomain.xml」)
socket或xmlsocket請求——》Security.loadPolicyFile(「xmlsocket://www.xxx.com:port」)
怎麼將Socke策略文件發給Flash Player
Flash Player在你的socket.connect("domain",port)運行以前,會按照前面描述的三個過程向你的socket服務器的843端口(聽說Adobe已經向相關管理機構申請保留843端口給Flash Player用)發送一個字符串 "<policy-file-request/>",這個時候若是你有一個服務在監聽843端口那麼收到這個字符串以後,直接按照XML格式發回策略文件就解決了。(注意發回的時候記得加一個截止字符"\0")
固然你也能夠不用843端口本身設置一個端口。由於Flash Player若是在843端口得不到信息,就會檢查你是否在你的Flash文件裏面本身添加了指定的獲取通道,你能夠定義一個本身的端口。不過這個時候你不能用http方式,而要用xmlsocket方式。(至關於自動幫你新建了一個xmlsocket對象,而後連接你指定的主機和端口)。好比你想用1234端口能夠在你的Flash裏面加這一句Security.loadPolicyFile(「xmlsocket://www.xxx.com:1234」),須要注意的是這一句要加在你的socket.connect前面。
還有最後一個辦法,就是在你的socket鏈接端口監聽這個請求。好比你用的是socket.connect("192.168.1.100",8888),那麼在你的服務器加一段接收字符串"<policy-file-request/>"的代碼,當接到這個字符串時將策略文家按照xml格式發到客戶端。
關於策略文件的格式(能夠在Flash CS3幫助裏面的Flash Player安全性——》控制權限概述中找到)
一、針對web應用的策略文件
下面的示例顯示了一個策略文件,該文件容許訪問源自 *.iflashigame.com 和 192.0.34.166 的 SWF 文件。
<?xml version="1.0"?>
<cross-domain-policy>
<allow-access-from domain="*.iflashigame.com" />
<allow-access-from domain="192.0.34.166" />
</cross-domain-policy>
注意事項:
默認狀況下,策略文件必須命名爲 crossdomain.xml,而且必須位於服務器的根目錄中。可是,SWF 文件能夠經過調用 Security.loadPolicyFile() 方法檢查是否爲其它名稱或位於其它目錄中。跨域策略文件僅適用於從其中加載該文件的目錄及其子目錄。所以,根目錄中的策略文件適用於整個服務器,可是從任意子目錄加載的策略文件僅適用於該目錄及其子目錄。
策略文件僅影響對其所在特定服務器的訪問。例如,位於 https://www.adobe.com:8080/crossdomain.xml的策略文件只適用於在端口 8080 經過 HTTPS 對 www.adobe.com 進行的數據加載調用。
二、針對Socket的策略文件
<cross-domain-policy>
<allow-access-from domain="*" to-ports="507" />
<allow-access-from domain="*.example.com" to-ports="507,516" />
<allow-access-from domain="*.example2.com" to-ports="516-523" />
<allow-access-from domain="www.example2.com" to-ports="507,516-523" />
<allow-access-from domain="www.example3.com" to-ports="*" />
</cross-domain-policy>
這個策略文件是指定容許哪些域的主機經過那些端口連接。 html
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket; public class SecurityXMLServer implements Runnable { private ServerSocket server; private BufferedReader reader; private BufferedWriter writer; private String xml; public SecurityXMLServer() { String path = "policyfile文件路徑"; //此處的換成相應的讀取xml文檔的方式如dom或sax //xml = readFile(path, "UTF-8"); /** 注意此處xml文件的內容,爲純字符串,沒有xml文檔的版本號 */ xml="<cross-domain-policy> " +"<allow-access-from domain=\"*\" to-ports=\"1025-9999\"/>" +"</cross-domain-policy> "; System.out.println("policyfile文件路徑: " + path); System.out.println(xml); //啓動843端口 createServerSocket(843); new Thread(this).start(); } //啓動服務器 private void createServerSocket(int port) { try { server = new ServerSocket(port); System.out.println("服務監聽端口:" + port); } catch (IOException e) { System.exit(1); } } //啓動服務器線程 public void run() { while (true) { Socket client = null; try { //接收客戶端的鏈接 client = server.accept(); InputStreamReader input = new InputStreamReader(client.getInputStream(), "UTF-8"); reader = new BufferedReader(input); OutputStreamWriter output = new OutputStreamWriter(client.getOutputStream(), "UTF-8"); writer = new BufferedWriter(output); //讀取客戶端發送的數據 StringBuilder data = new StringBuilder(); int c = 0; while ((c = reader.read()) != -1) { if (c != '\0') data.append((char) c); else break; } String info = data.toString(); System.out.println("輸入的請求: " + info); //接收到客戶端的請求以後,將策略文件發送出去 if(info.indexOf("<policy-file-request/>") >=0) { writer.write(xml + "\0"); writer.flush(); System.out.println("將安全策略文件發送至: " + client.getInetAddress()); } else { writer.write("請求沒法識別\0"); writer.flush(); System.out.println("請求沒法識別: "+client.getInetAddress()); } client.close(); } catch (Exception e) { e.printStackTrace(); try { //發現異常關閉鏈接 if (client != null) { client.close(); client = null; } } catch (IOException ex) { ex.printStackTrace(); } finally { //調用垃圾收集方法 System.gc(); } } } } //測試主函數 public static void main(String[] args) { new SecurityXMLServer(); } }