flash底層安全機制強制要求flash通信或者跨域訪問時,必須從服務端拿到安全策略文件,默認是flash會向服務端843發送<policy-file-request/>報文,當服務端843不開放,或者安全時間(3秒)內無返回時,如果是socket通信,flash會向服務端socket指定端口發送請求報文<policy-file-request/>,如果服務端無返回或返回不是安全策略文件,那麼flash將報安全沙箱錯誤。安全策略文件內容如下:
<cross-domain-policy>
<allow-access-from domain="*" to-ports="*"/>
</cross-domain-policy>
其中domain指定可訪問的跨域地址,to-ports爲指定可訪問的跨域端口,
java服務端一般做法是開啓843端口服務,網上代碼如下:(此代碼測試有嚴重的bug,下面會指出)
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;
private int stop = 0;
public SecurityXMLServer() {
xml = "<cross-domain-policy>"
+ "<allow-access-from domain=\"*\" to-ports=\"*\"/>"
+ "</cross-domain-policy>\0";
// System.out.println(xml);
// 啓動843端口
createServerSocket(843);
new Thread(this).start();
}
// 啓動服務器
private void createServerSocket(int port) {
try {
server = new ServerSocket(port);
System.out.println("服務監聽843端口:" + port);
} catch (IOException e) {
e.printStackTrace();
try {
server.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
// 啓動服務器線程
public void run() {
while (true) {
if (stop == 1)
break;
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);
writer.flush();
// System.out.println("將安全策略文件發送至: " +
// client.getInetAddress());
} else {
writer.write("Quest Error \0");
writer.flush();
// System.out.println("請求無法識別: "+client.getInetAddress());
}
client.close();
} catch (Exception e) {
try {
// 發現異常關閉連接
if (client != null) {
client.close();
client = null;
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
public ServerSocket getServer() {
return server;
}
public void setStop(int stop) {
this.stop = stop;
}
}
這段代碼的bug出現在單線程監聽843,一旦客戶端假死,簡單可測試的方法就是連上後突然斷線,停電,那麼843端口被佔用,無法訪問,主要是 while ((c = reader.read()) != -1)
reader.read()當TCP異常時,是無法監測到的,斷線/停電等情況都會造成reader.read()阻塞,客戶端無消息到達,服務端也無法監測到客戶端的狀態,所以會一直阻塞,之前我的一個項目就是因爲用同樣的方式去讀取843安全請求信息,所以經常出現843阻塞,得靠重啓843服務來維護。其實Socket中有一個方法,setSoTimeout(毫秒),此方法設置了連接超時時間,
默認是setSoTimeout(0),只要在client = server.accept();後面加client.setSoTimeout(300);就不會再出現843阻塞無法連接的情況了!