Flex与java进行socket通信完成以断点续传方式的文件上传
简单的文件上传是将整个文件在一起此请求中将文件上传至服务器中,而对户外作业平台而言,网络的稳定性是一个问题,加之平台的大文件性,故而在该平台中采用断点续传方式来上传文件较为合适。 断点续传简单来讲,客户端与服务器端通信,了解到已传输文件的大小后,而后在按照一定的文件块大小对剩余未传输的文件进行分块传输,服务器端则将这些块文件一点点写入到同一个文件中,从而形成一个完成文件,达到断点续传的目的。客户端逻辑示意如下所示: Flex的文件上传下载会使用到FileReference,而在FlashPlayer10以后提供了Load方法和data属性。在FileReference执行完load方法后,data中便存储了FileReference所代表的文件的数据,其为ByteArray对象,即我们可以以字节的形式访问Flex加载的文件,而这也为在断点续传文件时对文件进行分块处理提供了可能性。 Flex与java通信上传文件的实现方式可以有多种,本文采用socket通信方式来传输文件。Flex端代码如下所示: //利用socket socket = new Socket; socket.connect("12.156.53.29",1234); //连接服务器 //监听是否连接 socket.addEventListener(Event.CONNECT,function conn(){ //发送名称 socket.writeUTF(fileReference.name); socket.flush(); //文件大小 socket.writeUTF(String(fileReference.data.length)); socket.flush(); }); //监听接受数据 socket.addEventListener(ProgressEvent.SOCKET_DATA,function receiveData(){ //已上传大小 var len:String = socket.readUTF(); if(len == "0"){ if(fileReference.data.length < 1024){ socket.writeBytes(fileReference.data); }else{ socket.writeBytes(fileReference.data,1024); } socket.flush(); }else{ if((fileReference.data.length - uint(len)) > 1024){ socket.writeBytes(fileReference.data,uint(len),1024); }else{ socket.writeBytes(fileReference.data,fileReference.data.length - uint(len)); } socket.flush(); } });//监听连接关闭 socket.addEventListener(Event.CLOSE,functioncloseConn(){ }); 在flash.net包中存在Socket类,在文档的描述中,我们可以了解到socket通信需要使用套接字策略文件。在实际的socket通信过程中,我们在客户端不管发送什么信息,在服务端的socket第一次接收的信息都会是<policy-file-request/>。这个信息是在要求服务端提供给客户端socket通信的策略文件,在该文件中指定通信的端口号等信息。这个过程涉及到Flash Player安全机制,不过多讲述,了解到flex进行跨域socket通信时默认必须要在843端口上接收Flash Player的策略文件请求。此处需要注意的是对策略文件的请求和断点续传过程主动发起的请求同服务端的socket连接是两个独立的连接,在处理完策略文件请求连接后,我们要关闭策略文件请求的连接,这样Flash Player会自动重新连接,从而可实现断点续传的socket连接,否则我们的主动请求将无法连接上。 针对上面术的内容,我做了这样处理:建立两个两个listener,一个监听对策略文件的请求,一个监听对断点续传socket连接的请求,后者是我们的主请求。在每个监听器使用多线程处理,每次接受到socket连接请求,就会创建一个线程用于处理策略文件请求或者断点续传请求。 Web.xml中配置listener <!-- 大文件上传端口监听器 -->
<listener>
<display-name>myListener</display-name>
<listener-class>com. fileoperation.LargeFileUploadListener</listener-class>
</listener>
<!-- 大文件上传端口安全策略监听器 -->
<listener>
<display-name>policyListener</display-name>
<listener-class>com. fileoperation.LargeFileUploadPolicyListener</listener-class>
</listener>
LargeFileUploadPolicyListener.java: package com.fileoperation; import java.net.ServerSocket; import java.net.Socket; import javax.servlet.ServletContextEvent; import org.apache.log4j.Logger; public class LargeFileUploadPolicyListener extends javax.servlet.http.HttpServlet implements javax.servlet.ServletContextListener{ private static final long serialVersionUID = 1L; private static final Logger log = Logger.getLogger(LargeFileUploadListener.class); private static Thread thread = null; @SuppressWarnings("deprecation") public void contextDestroyed(ServletContextEvent arg0) { if(thread != null){ thread = null; } } public void contextInitialized(ServletContextEvent arg0) { try { thread = new Thread() { public void run() { log.info("大文件上传侦听开始。。。。"); try{ ServerSocket policyServerSocket= new ServerSocket(Integer.parseInt("843"));//服务器套接字 Socket policyClientSocket = null; Socket clientSocket=null; while(true){ policyClientSocket = policyServerSocket.accept(); //获得客户端的请求的Socket log.info("已侦听到了客户端的请求。。。。。"); new MyPolicyServerThread(policyClientSocket); } }catch (Exception e) { log.error("接收大文件异常:",e); } } }; thread.start(); } catch (Exception e) { log.error("启动监听器异常:",e); } } } MyPolicyServerThread.java: package com. fileoperation; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.io.UnsupportedEncodingException; import java.net.Socket; import org.apache.log4j.Logger; public class MyPolicyServerThread extends Thread { private static final Logger log = Logger.getLogger(MyServerThread.class); private Socket socket; private final String policy_xml = "<policy-file-request/>"; private final String cross_xml = "<?xml version="1.0"?>" + "<cross-domain-policy>" + "<site-control permitted-cross-domain-policies="all"/>" + "<allow-access-from domain="*" to-ports="1234"/>" + "</cross-domain-policy> |