简单的文件上传是将整个文件在一起此请求中将文件上传至服务器中,而对户外作业平台而言,网络的稳定性是一个问题,加之平台的大文件性,故而在该平台中采用断点续传方式来上传文件较为合适。
断点续传简单来讲,客户端与服务器端通信,了解到已传输文件的大小后,而后在按照一定的文件块大小对剩余未传输的文件进行分块传输,服务器端则将这些块文件一点点写入到同一个文件中,从而形成一个完成文件,达到断点续传的目的。客户端逻辑示意如下所示:
Flex的文件上传下载会使用到FileReference,而在FlashPlayer10以后提供了Load方法和data属性。在FileReference执行完load方法后,data中便存储了FileReference所代表的文件的数据,其为ByteArray对象,即我们可以以字节的形式访问Flex加载的文件,而这也为在断点续传文件时对文件进行分块处理提供了可能性。
Flex与java通信上传文件的实现方式可以有多种,本文采用socket通信方式来传输文件。Flex端代码如下所示:
-
<spanstyle="font-size:12px;">//利用socket
-
socket=newSocket;
-
socket.connect("12.156.53.29",1234);//连接服务器
-
-
//监听是否连接
-
socket.addEventListener(Event.CONNECT,functionconn(){
-
-
//发送名称
-
socket.writeUTF(fileReference.name);
-
socket.flush();
-
//文件大小
-
socket.writeUTF(String(fileReference.data.length));
-
socket.flush();
-
-
});
-
-
//监听接受数据
-
socket.addEventListener(ProgressEvent.SOCKET_DATA,functionreceiveData(){
-
-
//已上传大小
-
varlen:String=socket.readUTF();
-
if(len=="0"){
-
if(fileReference.data.length<1024){
-
socket.writeBytes(fileReference.data);
-
}else{
-
socket.writeBytes(fileReference.data,0,1024);
-
}
-
socket.flush();
-
}else{
-
if((fileReference.data.length-uint(len))>1024){
-
socket.writeBytes(fileReference.data,uint(len),1024);
-
}else{
-
socket.writeBytes(fileReference.data,uint(len),fileReference.data.length-uint(len));
-
}
-
socket.flush();
-
}
-
-
});
-
</span><prename="code"class="html">//监听连接关闭
-
-
socket.addEventListener(Event.CLOSE,functioncloseConn(){});
-
</pre>
在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
-
<spanstyle="font-size:12px;">
-
<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></span>
LargeFileUploadPolicyListener.java:
-
packagecom.fileoperation;
-
importjava.net.ServerSocket;
-
importjava.net.Socket;
-
importjavax.servlet.ServletContextEvent;
-
importorg.apache.log4j.Logger;
-
-
publicclassLargeFileUploadPolicyListenerextendsjavax.servlet.http.HttpServletimplementsjavax.servlet.ServletContextListener{
-
-
-
privatestaticfinallongserialVersionUID=1L;
-
privatestaticfinalLoggerlog=Logger.getLogger(LargeFileUploadListener.class);
-
privatestaticThreadthread=null;
-
-
@SuppressWarnings("deprecation")
-
publicvoidcontextDestroyed(ServletContextEventarg0){
-
if(thread!=null){
-
thread=null;
-
}
-
}
-
-
publicvoidcontextInitialized(ServletContextEventarg0){
-
try{
-
thread=newThread(){
-
publicvoidrun(){
-
log.info("大文件上传侦听开始。。。。");
-
try{
-
ServerSocketpolicyServerSocket=newServerSocket(Integer.parseInt("843"));
-
-
SocketpolicyClientSocket=null;
-
-
SocketclientSocket=null;
-
while(true){
-
-
policyClientSocket=policyServerSocket.accept();
-
log.info("已侦听到了客户端的请求。。。。。");
-
newMyPolicyServerThread(policyClientSocket);
-
}
-
}catch(Exceptione){
-
log.error("接收大文件异常:",e);
-
}
-
}
-
};
-
thread.start();
-
}catch(Exceptione){
-
log.error("启动监听器异常:",e);
-
}
-
}
-
}
MyPolicyServerThread.java:
-
packagecom.fileoperation;
-
-
importjava.io.BufferedReader;
-
importjava.io.IOException;
-
importjava.io.InputStreamReader;
-
importjava.io.PrintStream;
-
importjava.io.UnsupportedEncodingException;
-
importjava.net.Socket;
-
-
importorg.apache.log4j.Logger;
-
-
publicclassMyPolicyServerThreadextendsThread{
-
-
privatestaticfinalLoggerlog=Logger.getLogger(MyServerThread.class);
-
privateSocketsocket;
-
-
privatefinalStringpolicy_xml="<policy-file-request/>";
-
privatefinalStringcross_xml="<?xmlversion=\"1.0\"?>"+
-
"<cross-domain-policy>"+
-
"<site-controlpermitted-cross-domain-policies=\"all\"/>"+
-
"<allow-access-fromdomain=\"*\"to-ports=\"1234\"/>"+
-
"</cross-domain-policy>\0";
-
-
publicMyPolicyServerThread(Socketsocket){
-
this.socket=socket;
-
this.start();
-
}
-
-
@Override
-
publicvoidrun(){
-
try{
-
BufferedReaderreaderIn=newBufferedReader(newInputStreamReader(socket.getInputStream()));
-
PrintStreamprintOut=newPrintStream(socket.getOutputStream());
-
-
char[]by=newchar[22];
-
readerIn.read(by,0,22);
-
Strings=newString(by);
-
if(s.equals(policy_xml)){
-
System.out.println("接收policy-file-request认证");
-
printOut.print(cross_xml);
-
printOut.flush();
-
readerIn.close();
-
printOut.close();
-
socket.close();
-
System.out.println("完成policy-file-request认证");
-
}
-
-
}catch(UnsupportedEncodingExceptione){
-
e.printStackTrace();
-
}catch(IOExceptione){
-
e.printStackTrace();
-
}
-
}
-
}
上面是策略文件socket连接的处理过程,此过程是Flash Player默认发起的,在客户端无需我们人工干预,只需要在服务端进行处理即可,在上述策略文件中我们发现,其指定了to-ports=\"1234\",即指明了socket主动请求的socket端口号为1234,而在关闭此策略socket连接后,FlashPlayer重新连接的端口号即为1234了。下面的服务端处理过程是与我们的主动请求(断点续传)相关联的,在上文断点续传逻辑图中,只写明了客户端的逻辑,而服务端的逻辑实际上是与之相对对应的,而核心是java.io.RandomAccessFile将文件分批写入相应文件下。下面代码中发起的线程执行情况是与前文所讲Flex端的socket相互通信共同实现断点续传上传文件功能的。
LargeFileUploadListener.java
-
packagecom.fileoperation;
-
-
importjava.net.ServerSocket;
-
importjava.net.Socket;
-
importjavax.servlet.ServletContextEvent;
-
importorg.apache.log4j.Logger;
-
-
publicclassLargeFileUploadListenerextendsjavax.servlet.http.HttpServletimplementsjavax.servlet.ServletContextListener{
-
-
privatestaticfinallongserialVersionUID=1L;
-
privatestaticfinalLoggerlog=Logger.getLogger(LargeFileUploadListener.class);
-
privatestaticThreadthread=null;
-
-
@SuppressWarnings("deprecation")
-
publicvoidcontextDestroyed(ServletContextEventarg0){
-
if(thread!=null){
-
thread=null;
-
}
-
}
-
-
publicvoidcontextInitialized(ServletContextEventarg0){
-
try{
-
thread=newThread(){
-
publicvoidrun(){
-
log.info("大文件上传侦听开始。。。。");
-
try{
-
-
ServerSocketserverSocket=newServerSocket(Integer.parseInt("1234"));
-
SocketclientSocket=null;
-
while(true){
-
clientSocket=serverSocket.accept();
-
log.info("已侦听到了客户端的请求。。。。。");
-
-
newMyServerThread(clientSocket);
-
}
-
}catch(Exceptione){
-
log.error("接收大文件异常:",e);
-
}
-
}
-
};
-
thread.start();
-
}catch(Exceptione){
-
log.error("启动监听器异常:",e);
-
}
-
}
-
-
}
MyServerThread.java:
flex利用socket通信,并不需要像通过remoteObject方式访问java端服务一样配置相关服务,只需要在flex端的mxml或as文件中进行socket连接时写明连接的ip和端口即可进行通信,但需要注意的是需要对FlashPlayer所要求的策略文件进行相应处理。此外断点续传所要做的核心内容是将整个文件在一次请求中传递改为多次请求中分块传递,服务端利用相关类对分块文件进行整合即可。
分享到:
相关推荐
flex与JAVA的SOCKET通信,详细讲解flex与JAVA的SOCKET通信
flex利用socket进行文件断点续传,带进度条,本地代码能完整运行,Flash Builder 4 ,eclipse ,jdk1.6,java代码偶尔会报线程错误,但是不会影响上传功能
Flex和java的socket通信 Flex和java的socket通信
Flex 利用socket实现断点续传源码,有进度条,在本地代码可以完整运行,Flash Builder 4 ,eclipse ,jdk1.6,java代码偶尔会报线程错误,但是不会影响上传功能
前端用flash实现,后端用java实现,socket通讯
flex+java的socket通信,文本中说明了文件构成,可实现基本的flex与java基于socket的通信
Flex与Java Socket通信 很适用的例子啊
Flex与Java实现通信,Flex与Java实现通信,Flex与Java实现通信
Flex和java的socket通信 连接 单向通信 多客户通信 一个简单的聊天室
1.背景:Flex Socket通信及安全策略,使用flex实现客户端,java实现服务端; 2.重点解决安全策略问题:将flash发布为html格式后,本地访问页面后,一般可以与服务器进行socket通信;但是部署到tomcat服务器上后无法...
flex与java通信
Flex+Servlet断点续传Demo
HTTP断点续传原理,另附上AS3+Flash Player+AIR制作的一个断点续传小程序源码
Flex+Java 文件上传
最简单的BlazeDS实现flex与java通信..无积分下载...最简单的BlazeDS实现flex与java通信..无积分下载...最简单的BlazeDS实现flex与java通信..无积分下载...最简单的BlazeDS实现flex与java通信..无积分下载...最简单的...
NULL 博文链接:https://xiegangthrille.iteye.com/blog/660219
Flex的AS3与Java的Socket通信
flex 通信方式 文本文件 java flex 通信方式 文本文件 java
NULL 博文链接:https://fengyunxiao.iteye.com/blog/462763