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阻塞无法连接的情况了!