flash socket通讯安全沙箱问题解决(附带案例)

一、flash socket通讯安全沙箱问题解决

        flash发起socket通讯的三个过程:

             1、当封装在页面的flash发起socket通讯请求的时候会寻找服务器端843端口, 获取crossdomain.xml文件。

             2、当服务器没有开启843的时候,flash player会检查发起请求的swf文件中有没有使用Security.loadPolicyFile(xmlsocket://127.0.0.1:4299)

                 来加载策略文件crossdomain.xml。

             3、如果没有就会看这个发起请求的swf要连接的目标端口有没有策略文件。

           如果上述三个步骤都没有找到策略文件,那么出现连接失败并出现错误提示:

            [SecurityErrorEvent type="securityError" bubbles=false cancelable=false eventPhase=2 text="Error #2048"]


二、  产生该问题的原因:

                新版的flash player,当flash文件要进行socket通讯的时候,需要向服务器端 获取crossdomain.xml文件,如果找不到就会出现上述问题。

             (老版的flash player无论你采用的是http请求方式或者xmlsocket socket方式, 他们都共用一个安全策略文件,这个策略文件只要你放在主域的目录下就行,

                  而新版的要求,如果你使用http请求方式需要把策略文件放在目录下面,如果你使用的socket请求方式就必须通过socket端口来接收这个策略文件。
       
             其对应的调用的方式为:
                   http请求:Security.loadPolicyFile("http://www.xxx.com/crossdomain.xml");
                  socket或xmlsocket请求:Security.loadPolicyFile("xmlsocket://www.xxx.com:port");)


三、那么怎么将socket策略文件发送给flash player。

        三种方法:

                一、使用默认843端口

                    flash player在你的socket.connect(address,port);运行之前,会按照三个过程向你的socket 服务器的843端口发送一个字符串 "<policy-file-request/>" ,

                    这个时候如果你有一个服务器在监听843端口那么受到这个字符串之后,直接按照xml格式发挥策略文件就解决了。

               二、使用自定义端口(推荐使用)

                      当然你也可以自己设置一个端口,不过这个时候不能用Http方式,而要用xmlsocket方式。相当于自动帮你新建一个xmlsocket对象,

                      然后连接你指定的主机和端口,  比如你想用1234端口可以在你的flash里面加这一句Security.loadPolicyFile("xmlsocket://www.xxx.com:1234")

                          需要注意的是这一句要加在你的socket.connect()前面。

              三、代码发送策略文件。

                   在你的socket连接端口监听这个请求,比如你用的是socekt.connect("127.0.0.1",3333);

                   那么在你的服务器加一段接受字符串"<policy-file-request/>"的代码,当接收到这个字符串 的时候将策略文件按照xml格式发到客户端。


四、如何配置安全策略文件

            1、针对web应用的策略文件

                     示列为策略文件允许访问源自:*game.com和192.168.1.1的swf文件
                    <?xml version = "1.0" encoding = "utf-8"?>
                   <!DOCTYPE cross-domain-policy SYSTEM "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">
                            <cross-domain-policy>
                              <allow-access-from domain="*.game.com" />
                             <allow-access-from domain="192.168.1.1" />
                    </cross-domain-policy>
               注意事项:

                    默认情况下,策略文件必须命名为 crossdomain.xml,并且必须位于服务器的根目录中。但是,SWF 文件可以通过调用

                   Security.loadPolicyFile() 方法检查是否为其它名称或位于 其它目录中。跨域策略文件仅适用于从其中加载该文件的目录

                   及其子目录。因此,根目录中的策略文件适用于整个服务器, 但是从任意子目录加载的策略文件仅适用于该目录及其子目录。


            2、针对socket的策略文件

                    <?xml version = "1.0" encoding = "utf-8"?>
                    <!DOCTYPE cross-domain-policy SYSTEM "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">

                      <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.example3.com" to-ports="*" />
                    </cross-domain-policy>

                     这个策略文件是指定允许哪些域的主机通过哪些端口链接。

                     

五、示例代码


java   socket服务端:

安全策略服务器:
public class SecurityServer
{
	private int count = 0;
	public  String xml = "";
	private InputStream is;
	private OutputStream os;

	public void start() throws Exception
	{
		xml += "<cross-domain-policy>";
		xml += "<allow-access-from domain=\"*\" to-ports=\"*\" />";
		xml += "</cross-domain-policy>";

		ServerSocket serverSocket = new ServerSocket(4299);
		System.out.println("等待用户连接``并发送策略文件``````");
		while (true)
		{
			try
			{
				Socket socket = serverSocket.accept();
				count++;
				this.is = socket.getInputStream();
				this.os = socket.getOutputStream();
				byte[] temp = new byte[300];
				this.is.read(temp);
				this.os.write(this.xml.getBytes("utf-8"));
				this.os.flush();
				this.os.close();
				this.is.close();
				socket.close();
			} catch (Exception e)
			{
				System.out.println("服务器发生异常");
			}
		}
	}
	public static void main(String[] args)
	{
		try
		{
			new SecurityServer().start();
		} catch (Exception e)
		{
			System.out.println("Socket发生异常:" + e);
		}
	}
}


主连接服务器:
public class ServerJava
{
	private int count =0;
	
	public void start() throws Exception
	{
		ServerSocket serverSocket = new ServerSocket(4399);
		System.out.println("等待用户连接````````");
		while (true)
		{
			try
			{
				Socket socket = serverSocket.accept();
				
				count++;
				System.out.println("连接成功``数量: `````"+count);
				
				ServerThread thread = new ServerThread(socket);
				thread.start();
			} catch (Exception e)
			{
				System.out.println("服务器发生异常");
			}
		}
	}
	public static void main(String[] args)
	{
		try
		{
			new ServerJava().start();
		} catch (Exception e)
		{
			System.out.println("Socket发生异常:" + e);
		}
	}
}

服务端读取客户端数据:
public class ServerThread extends Thread
{
	private Socket socket;
	private BufferedReader input;
	private PrintWriter output;
	private OutputStream os;
	private InputStream is;
	
	public ServerThread(Socket socket)
	{
		this.socket = socket;
	}
	public void run()
	{
		System.out.println("---------------启动一个线程-----------------");
		try
		{
			this.os = this.socket.getOutputStream();
			this.is = this.socket.getInputStream();
			byte[] temp = new byte[1000];
			int len = 0;
			StringBuffer msg = new StringBuffer();

			while ((len = this.is.read(temp)) > 0)
			{
				msg.append(new String(temp, 0, len,"UTF-8"));
				if(len<1000){
					this.os.write(msg.toString().getBytes("UTF-8"));
					this.os.flush();
					msg = new StringBuffer();
				}
			}
		} catch (Exception e)
		{
			System.out.println("子线程发生异常");
			try
			{
				input.close();
				output.close();
			} catch (Exception ex)
			{
				System.out.println("关闭资源发生异常");
			}
			System.out.println("子线程结束了");
		}
	}
}


as3客户单端代码:

package {
	import flash.net.Socket;
	import flash.events.ProgressEvent;
	import flash.events.Event;
	import flash.utils.ByteArray;
	import flash.display.Sprite;
	import flash.system.Security;
	import flash.text.TextField;
	import flash.events.MouseEvent;
	public class ClientSocket extends Sprite {
		private var count:uint=0;
		private var clientSocket:Socket;
		private var readBytes:ByteArray = new ByteArray();
		private var writeBytes:ByteArray = new ByteArray();
		public function ClientSocket() {
			conn.addEventListener(MouseEvent.CLICK,connServer);
			send.addEventListener(MouseEvent.CLICK,sendToServer);
		}

		private function connServer(evt:MouseEvent):void {
			clientSocket = new Socket();
			Security.allowDomain("*");
			Security.loadPolicyFile("xmlsocket://127.0.0.1:4299")
			clientSocket.connect("127.0.0.1",4399);
			clientSocket.addEventListener(Event.CONNECT,successConn);
			clientSocket.addEventListener(ProgressEvent.SOCKET_DATA,reviceData);
		}

		private function successConn(evt:Event):void {
			count++;
			dyText.text="连接成功"+count+"\n";
		}
		private function sendToServer(evt:Event):void {
			var charContext=inputText.text;
			dyText.text=dyText.text+charContext+"\n";
			//utf-8转码
			clientSocket.writeUTFBytes(charContext);
			clientSocket.flush();
		}

		private function reviceData(evt:Event):void {
			
			trace(totalLen+"======revice message===============");
            var totalLen:uint=clientSocket.bytesAvailable;
			server.text=clientSocket.readUTFBytes(totalLen);
		}
	}
}

将swf文件发布到网页上进行测试

你可能感兴趣的:(java,socket,Web应用,actionscript)