Flex利用socket实现断点续传(二)


上一篇博文中展示给大家ActionScript的代码,当初学的时候就学了半年多,又两年多没有使用Flex,其中一些东西有所生疏 不过上篇博文中的内容对于有一定Flex功底的人来说还是比较简单的。闲话少续下面展示java代码。首先配置listener共两个。

 

<!-- 大文件上传端口监听器 -->
   	<listener>
	  	<display-name>myListener</display-name>
	  	<listener-class>com.ibm.rise.workplace.fileoperation.LargeFileUploadListener</listener-class>
  	</listener>
	<!-- 大文件上传端口安全策略监听器 -->
   	<listener>
	  	<display-name>myListener</display-name>
	  	<listener-class>com.ibm.rise.workplace.fileoperation.LargeFileUploadPolicyListener</listener-class>
  	</listener>
  	

摘自东哥的博文:

在flash.net包中存在Socket类,在文档的描述中,我们可以了解到socket通信需要使用套接字策略文件。在实际的socket通信过程中,我们在客户端不管发送什么信息,在服务端的socket第一次接收的信息都会是<policy-file-request/>。这个信息是在要求服务端提供给客户端socket通信的策略文件,在该文件中指定通信的端口号等信息。这个过程涉及到Flash Player安全机制,不过多讲述,了解到flex进行跨域socket通信时默认必须要在843端口上接收Flash Player的策略文件请求。此处需要注意的是对策略文件的请求和断点续传过程主动发起的请求同服务端的socket连接是两个独立的连接,在处理完策略文件请求连接后,我们要关闭策略文件请求的连接,这样Flash Player会自动重新连接,从而可实现断点续传的socket连接,否则我们的主动请求将无法连接上。


针对上面术的内容,我做了这样处理:建立两个两个listener,一个监听对策略文件的请求,一个监听对断点续传socket连接的请求,后者是我们的主请求。在每个监听器使用多线程处理,每次接受到socket连接请求,就会创建一个线程用于处理策略文件请求或者断点续传请求。


 

LargeFileUploadListener

 

package com.ibm.rise.workplace.fileoperation;

import java.net.ServerSocket;  
import java.net.Socket;  
import javax.servlet.ServletContextEvent;  
import javax.servlet.ServletException;

public class LargeFileUploadListener extends javax.servlet.http.HttpServlet implements javax.servlet.ServletContextListener{  
  
	 private static final long serialVersionUID = 1L;  
	   private static Thread thread = null;  
	 
	   @Override
	   public void init() throws ServletException {
		   try {     
	            thread = new Thread() {   
	                public void run() { 
	                     try{ 
	                 
	                         ServerSocket serverSocket= new ServerSocket(Integer.parseInt("1234"));//服务器套接字     
	                       Socket clientSocket=null;     
	                         while(true){     
	                            clientSocket= serverSocket.accept();//获得客户端的请求的Socket     
	                            System.out.println("已侦听到了客户端开始上传文件的请求。。。。。"); 
	                            new MyServerThread(clientSocket);     
	                       }     
	                    }catch (Exception e) {   
	                       e.printStackTrace(); 
	                     }   
	                 }   
	             };   
	            thread.start();   
	         } catch (Exception e) {     
	         }    

	   }
	   @SuppressWarnings("deprecation")  
	   public void contextDestroyed(ServletContextEvent arg0) {  
	       if(thread != null){  
	           thread = null;  
	       }  
	   }  
	 
	   public void contextInitialized(ServletContextEvent arg0) {  
	       try {    
	           thread = new Thread() {  
	               public void run() {  
	            	   try{
	          			 //大文件上传侦听开始
				            ServerSocket serverSocket= new ServerSocket(Integer.parseInt("1234"));//服务器套接字  
				            Socket clientSocket=null;  
				            while(true){  
				                clientSocket= serverSocket.accept();//获得客户端的请求的Socket  
				                new MyServerThread(clientSocket);  
				            }  
						}catch (Exception e) {
						}
					}
				};
	           thread.start();  
	       } catch (Exception e) {    
	       }   
	   }  


}  


 MyPolicyServerThread

package com.ibm.rise.workplace.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;


/**
 * @Description 超大文件上传服务器端
 * MyServerThread.java
 * @date 2011 上午11:41:03
 */
public class MyPolicyServerThread extends Thread {

	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>\0";

	public MyPolicyServerThread(Socket socket) {
		this.socket = socket;
		this.start();
	}

	/**
	 * 请求信息接收顺序:
	 * A:服务器标记,LIST/FILE
	 * B:文件名称/文件列表信息
	 * C:文件大小
	 * D:操作人
	 * E:临界值
	 * F:MetaDataId
	 */
	@Override
	public void run() {
		try {
			BufferedReader readerIn = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			PrintStream printOut = new PrintStream(socket.getOutputStream());

			char[] by = new char[22];
			readerIn.read(by, 0, 22);
			String s = new String(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 (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
	
}


LargeFileUploadPolicyListener.java

 

package com.ibm.rise.workplace.fileoperation;

import java.net.ServerSocket;
import java.net.Socket;

import javax.servlet.ServletContextEvent;


/**
 * @Description 大文件上传监听端口
 * LargeFileUploadListener.java
 * @date 2011 上午11:54:43
 */
public class LargeFileUploadPolicyListener extends javax.servlet.http.HttpServlet implements javax.servlet.ServletContextListener{

 /**
  */
 private static final long serialVersionUID = 1L;
 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() {
     try{
      ServerSocket policyServerSocket= new ServerSocket(Integer.parseInt("843"));//服务器套接字
      
               Socket policyClientSocket = null;
               
               Socket clientSocket=null;  
               while(true){  
                   
                policyClientSocket = policyServerSocket.accept(); //获得客户端的请求的Socket 
       new MyPolicyServerThread(policyClientSocket);
               }  
     }catch (Exception e) {
     }
    }
   };
   thread.start();
        } catch (Exception e) {  
        } 
 }
 
}



以下是上传的重点代码,上传文件的存储路径,以及文件上传大小的比较

package com.ibm.rise.workplace.fileoperation;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.Socket;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.util.StringTokenizer;

public class MyServerThread extends Thread {  
  
    private Socket socket;  
    private DataInputStream dataInputStream;
    private DataOutputStream dataOutputStream;
    
    
    public MyServerThread(Socket socket) throws IOException {  
        this.dataInputStream = new DataInputStream(socket.getInputStream());
        this.dataOutputStream = new DataOutputStream(socket.getOutputStream());
        this.start();
    }  
    @Override  
    public void run() {  
      
            RandomAccessFile randomAccessFile = null;  
            FileLock fileLock = null;
    		FileChannel fileChannel = null;  
            System.out.println("数据上传……");           
            try {  
              //读取名称
				String fileName = dataInputStream.readUTF();
				String comment =dataInputStream.readUTF();
				String fileSize = dataInputStream.readUTF();
                System.out.println(fileName);
				//检测上传文件是否存在
				String FilePath ="D:";
	            StringTokenizer st = new StringTokenizer(FilePath.toString(),"/");   
	    	    String   toAddPath = st.nextToken()+"/";   
	    	    String   toTestPath = toAddPath;   
	    	    while(st.hasMoreTokens()){   
	    	    	 toAddPath = st.nextToken()+"/";   
	    	    	 toTestPath += toAddPath;   
	    	          File inbox   =   new File(toTestPath);   
	    	          if(!inbox.exists()) {
	    	        	  inbox.mkdir();   
	    	          }
	    	     }  
	            
	    	    //检测上传位置
	    	    File file = new File( FilePath + "/" + fileName);
	            long position = 0;
	            
	            if(file.exists()){
	            	position = file.length();
	            }

	            //通知客户端已传大小
	            dataOutputStream.writeUTF(String.valueOf(position));
	            dataOutputStream.flush();
	
	            byte[] buffer = null;
	            int read = 0;
	            
	            while(true){
	            	//检测上传位置
	            	file = new File( FilePath + "/" + fileName);
	 	            position = 0;
	 	            if(file.exists()){
	 	            	position = file.length();
	 	            }
	 	            
	            	//rw代表写流(随机读写)
		            randomAccessFile  = new RandomAccessFile(file,"rw");
		            
		            fileLock = null;
		            fileChannel = null; 
		            fileChannel = randomAccessFile.getChannel();
		            //保证当前只有自己操作此文件
		            fileLock = fileChannel.tryLock();
		           
		            //拿到了文件锁,写入数据
		            if(fileLock != null){
			            randomAccessFile.seek(position);
			           
			            read = 0;
		            	buffer = new byte[1024*1024];
	            	if(!"0".equals(fileSize)){
			            		read = dataInputStream.read(buffer);
		            		randomAccessFile.write(buffer,0,read);
		            	}
			            if(fileLock != null){
	                        fileLock.release();
	                        fileLock = null;
	                    }
			            if(randomAccessFile != null){
	                        randomAccessFile.close();
	                        randomAccessFile = null;
	                    }
		            }   
		            
		            //检测已上传的大小
	            	file = new File( FilePath + "/" + fileName);
	 	            position = 0;
	 	            if(file.exists()){
	 	            	position = file.length();
	 	            }
	 	            System.out.println("文件  " + fileName + "  已传输  " + String.valueOf(position)+ "字节");
	 	            
	 	           
	 	            //判断文件是否传输完成
	 	            if(position >= Long.parseLong(fileSize)){
	 	            	 //文件传输完成
	 	            	System.out.println("文件  " + fileName + "  已传输完毕,总大小为" + String.valueOf(position) + "字节");
	 	            	dataOutputStream.writeUTF(String.valueOf(position));
	 	            	dataOutputStream.flush();
	 	            	System.out.println("通知客户端传输文件 ,最后一次" + String.valueOf(position));
	            		 break ;
	 	            }else{
	 	            	//通知客户端已传大小
	 	            	System.out.println("通知客户端传输文件" + String.valueOf(position));
	 	            	dataOutputStream.writeUTF(String.valueOf(position));
	 	            	dataOutputStream.flush();
	 	            }
	            }	// END WHILE
                  
            } catch (IOException e) {  
                // TODO Auto-generated catch block   
                e.printStackTrace();  
            } finally {
    			if (fileLock != null) {
    				try {
    					fileLock.release();
    					fileLock = null;
    				} catch (Exception e) {
    				}
    			}
    			try {
    				if (fileChannel != null) {
    					fileChannel.close();
    				}
    				if (randomAccessFile != null) {
    					randomAccessFile.close();
    				}
    				dataInputStream.close();
    				dataOutputStream.close();
    				socket.close();
    			} catch (Exception e) {
    			}
    }  
}
    }



 

在代码段:

 if(position >= Long.parseLong(fileSize)){
                 //文件传输完成
                System.out.println("文件  " + fileName + "  已传输完毕,总大小为" + String.valueOf(position) + "字节");
                dataOutputStream.writeUTF(String.valueOf(position));
                dataOutputStream.flush();
                System.out.println("通知客户端传输文件 ,最后一次" + String.valueOf(position));
                break ;
               }

之所以在文件上传完成以后还想客户端输出数据,主要是为了进度条的显示。如果没有这段代码进度条有可能就显示到99%,但实际文件已经传输完毕。

flex利用文件上传主要原理是监听socket通信,当客户端请求上传文件时flex连接socket 服务端监听到请求就开始发出响应接收文件,之所以能断点续传是使用RandomAccessFile读写文件,在上传文件之前先判断有没有该文件,如果有该文件上传了多少,传回给客户端以后在继续上传。

上一篇博客说使用配置文件在生成swf文件以后通过jsp调用会发生问题,问题就是:生成的swf文件读取的ip地址不会因为配置文件中的地址信息发生改变而进行改变,所以使用配置文件在jsp调用flex是行不通的。

java代码中偶尔还会出现一些线程的exception,但是并不会影响上传功能,因水平有限对线程不是很了解哪位找到解决方法欢迎留言指导,我在这里期待有高手能解决这个问题。

再次感谢东哥和wuhualong1314这位博友。源码地址:http://download.csdn.net/detail/jiudihanbing/6976597

你可能感兴趣的:(Flex利用socket实现断点续传(二))