最近在编写一个ftp客户端,已经实现了断点续传等功能,但是如果我想下载多个文件 它就会一个一个的下载 不能同时下载 然后就把建立连接 下载文件的方法写在了一个继承了Thread的类(DownloadThread)里,每次点击下载时就传入相应参数新建一个可以建立连接和下载文件的类(DownloadThread),可是这样做的话又成了这样的效果:点击一个文件,开始下载,再点击一个文件,上一个文件的进度条就停了,然后开始了新选中的文件的下载。请问怎么样才能实现多个文件的同时下载

解决方案 »

  1.   

    楼主首先要通过debug看看为什么新建一个DownloadThread的时候上一个会停掉。按理来说只要每个文件下载都创建一个新的DownloadThread类是可以实现多个文件同时下载的,因为你的DownloadThread已经继承了Thread,是个线程类,应该互不影响的
      

  2.   

    我之前也做过debug,是走到DownloadThread里的doconn(链接ftp服务器)时上一个下载中的文件就停掉了,看那意思就好像同一个ip(客户端),只能创建一个socket链接到服务端的指定端口上一样,有点不太明白它为什么会停掉
      

  3.   

    那可能就是FTP服务器设定了单个IP一次只能下载一个文件的原因,FTP服务器为了减少下载压力经常这样设置的,实际上你的线程没有终止而是一直在等待接收数据,只是FTP服务器关闭数据传输通道了因为通道被你新建的DownloadThread占据了,所以之前的下载线程的进度条也就当然停止了。
      

  4.   

    不是的,我也曾经这样尝试过:将项目拷贝到另一个eclipse中,然后启动两个eclipse中,在两个eclipse中分别其它客户端,然后分别下载不同的文件,结果这样是可以同时下载的
      

  5.   

    class DownLoadThread extends Thread {
    public static Socket ftpSocket;
    public static ServerSocket serverSocket;
    public static Socket dataSocket;
    public static InputStream serverInput;
    public static PrintStream serverOutput;
    public static BufferedReader serverReader;
    public static boolean passiveFlag = true;
    public static String savepath;
    public DownLoadThread(Socket socket, String savepath) {
    ftpSocket = socket;
    this.savepath = savepath;
    this.start();
    }
    public void run() {
    try {
    serverOutput = new PrintStream(new BufferedOutputStream(ftpSocket.getOutputStream()), true, "GBK");
    serverReader = new BufferedReader(new InputStreamReader(ftpSocket.getInputStream()));
    readRespond();
    doLoginFTP("ftptest", "ftptest");
    } catch(Exception e) {
    e.printStackTrace();
    }

    }
    /**
     * 执行登录
     * @param user
     * @param pswd
     * @return
     */
    public boolean doLoginFTP(String user, String pswd) {
    String responseStr = doFTPCommand("USER " + user);
    if(responseStr.length() > 0) {
    responseStr = doFTPCommand("PASS " + pswd);
    if(responseStr.length() > 0){
    return true;
    }
    }
    return false;
    }
    /**
     * 下载指定文件
     * @param filepath
     * @param savepath
     */
    public void download(String filepath, String savepath) {
    String filename = filepath.substring(filepath.lastIndexOf("/") + 1, filepath.length());
    BufferedInputStream data_input = null;
    BufferedOutputStream data_output = null;
    byte[] temp = new byte[Constant.TEMP_BYTE_LENGTH];
    try {
    doFTPCommand("TYPE I");
    dataSocket = getDataSocket();
    doFTPCommand("RETR " + filepath);
    data_input = new BufferedInputStream(dataSocket.getInputStream());
    data_output = new BufferedOutputStream(new FileOutputStream(new File(savepath + File.separator + filename)));
    int read = 0;
    while((read = data_input.read(temp, 0, temp.length)) != -1) {
    data_output.write(temp, 0, read);
    data_output.flush();
    }
    data_output.close();
    readRespond();
    } catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();


    }
    /**
     * 得到传输数据的Socket
     * <br>分两种情况
     * <br>ftp链接分为两种模式:主动模式和被动模式
     * <p>主动模式(使用PORT命令):
     * <br>客户端链接服务端后,客户端打开某个端口供服务端链接以传输数据
     * <br>所以在这种模式下要根据客户端打开的端口首先得到ServerSocket,然后得到传输数据的Socket
     * <br>serverSocket = new ServerSocket(port);
     * <br>dataSocket = serverSocket.accept();
     * <p>被动模式(使用PASV命令):
     * <br>客户端链接服务端后,服务端打开某个端口供客户端链接以传输数据
     * <br>所以在这种模式下要根据服务端打开的端口和服务端IP直接得到传输数据的Socket
     * <br>执行PASV命令,得到如下格式的信息
     * <br>227 Entering Passive Mode (127,0,0,1,5,31)
     * <br>然后解析此信息,根据IP和port
     * <br>dataSocket = new Socket(address, port);
     * @return
     * @throws IOException 
     * @throws UnknownHostException 
     */
    private Socket getDataSocket() throws UnknownHostException, IOException {
    if(passiveFlag){
    String responseStr = doFTPCommand("PASV");
    int index = responseStr.indexOf("(");
    int lastindex = responseStr.lastIndexOf(")");
    String str = responseStr.substring(index + 1, lastindex);
    String address = 
    str.split(",")[0] + "." + 
    str.split(",")[1] + "." +
    str.split(",")[2] + "." +
    str.split(",")[3];
    int port = Integer.parseInt(str.split(",")[5]) + 256 * Integer.parseInt(str.split(",")[4]);
    dataSocket = new Socket(address, port);
    } else {
    serverSocket = new ServerSocket(123);
    dataSocket = serverSocket.accept();
    }
    return dataSocket;
    }
    /**
     * 执行FTP命令
     * @param command
     */
    public String doFTPCommand(String command) {
    System.out.println("Client:--->\n" + command + "\n");
    sendRequest(command);
    String responStr = readRespond();
    System.out.println("Server:<---\n" + responStr + "\n");
    return responStr;
    }
    /**
     * 向服务端发送命令
     * @param request
     * @return
     */
    public void sendRequest(String request){
    serverOutput.print(request + "\r\n");
    serverOutput.flush();
    }
    public String readRespond() {
    boolean isMultiLine = false;
    try { 
    if (ftpSocket.isClosed())
    throw new IOException("Server Disconnected!");
    String str = serverReader.readLine() + '\n';
    String result_str = str;
    if (str != null && str.length() >=4 && str.charAt(3) == '-') {
    isMultiLine = true;
    String respond_no = str.substring(0, 3);
    do {
    str = serverReader.readLine() + '\n';
    result_str = result_str +  str; 
    } while(!(str.length() >= 4 && str.substring(0, 3).equals(respond_no) && str.charAt(3) == ' '));

    // 读取服务器反馈以"XXX "开头的剩余部分。
    while (isMultiLine && serverReader.ready()) {
    str = serverReader.readLine();
    result_str = result_str +  str;
    }
    return result_str;
    } catch(Exception e) {
    return "";
    }
    }
    }
      

  6.   

    楼主能解析一下为什么这些要定义成static吗?static表示是类共享的变量,就是说这个类的所有实例都共享这些变量的,线程类没必要啊!
      

  7.   

    我哭了!我真的哭了!我怎么把它设成了static啊!不用试了,肯定是这个原因了!折腾了三四天的时间都没有解决,还又找线程的同步看,线程池看,我咋就没看看我这变量都是咋定义的呢?!当局者迷旁观者清啊,mochibing兄,感激之情难以言表,结贴给分!