0

我目前正在开发基于包 commons.net 的 ftp 客户端,以便运行测试以查看连接速度。基本上我的 ftp 测试包括连接到服务器,登录它,然后根据需要开始一个下载/上传周期,直到用户决定通过按钮停止它,然后当前周期将结束,所以测试。

但是,在运行这些测试时,出现了需要超时机制的情况。服务器正在传输文件,并在它确实完成之前发送返回码 226(传输完成)。

所以我的线程仍然卡住,当它不再可能时试图清空 inputStream。

我的想法是在下载过程中启动一个线程计时器,每次将一个字节传输到我的客户端时都会重置该计时器。当超时发生时,会引发一个异常左右,我的客户会对此做出反应,中止下载。

我已经阅读并尝试了许多解决方案,其中包括: - 从线程引发异常 -> 线程捕获异常而不是客户端;- 从线程中中断客户端,因此客户端引发了一个 interruptedException -> 似乎不起作用;- 使用超时的执行器 -> 因为我不知道下载的“正常”持续时间,所以我不能在我开始任务时把它交给执行器,而且,当我收到时必须重置计时器数据。

我在许多论坛上阅读了很多关于它的内容,但没有找到任何似乎适合并在这种情况下工作的解决方案。如果有人有另一种方法的想法?

这是我正在执行的操作的代码:

public double get(String fileName) {
    [...]
    org.apache.commons.net.io.Util.copyStream(stO,stD,client.getBufferSize(),
                this.localSize,
                new org.apache.commons.net.io.CopyStreamAdapter() {
                    public void bytesTransferred(long totalBytesTransferred,
                            int bytesTransferred,long streamSize) {
                        setProgressDL(totalBytesTransferred);
                        //reset the timer here
                    }
        });
[...]
}

这是我的一些测试代码,启动我的客户端:

public class TestFtp extends Thread {
[...]
public void run() {
    System.out.println("Launching FTP test");
    FtpClient client = new FtpClient(this.model, this, this.model.getFtpServer());
    try {
                    //Attempting connection on the server
        client.connect();
        try {
            // Attempting login
            client.login(this.model.getUsername(), this.model.getPassword());
            do {
                client.changeDirectory("get");
                                    // start timer
                client.get(this.model.getDistantFileName());
                                    // stop timer

                client.changeToParentDirectory();
                client.changeDirectory("put");
                client.set(this.model.getDistantFileName(),
                        this.model.getNewFileName());

                client.changeToParentDirectory();
                try {
                    // Little pause between each test
                    Thread.sleep(500);
                } catch (InterruptedException e) {}
                // Continue test until the user stops it
            } while (this.continuous);
            // Once the test is over, logout
            client.logout();

            } catch (FTPLoginException e) {
            // If login fails, the test ends
            System.out.println("Unable to login to the server.");
        }
    } catch (FTPConnectException e) {
        // If connection error, the test ends
        System.out.println("Unable to connect to the server.");
    }
}

如果有人可以提供帮助,请提前感谢您,如果您需要有关我的实际代码的更多信息,我可以在此处提供更多信息。

4

2 回答 2

0

如果您不想抛出不必要的异常,您应该使用一个布尔标志来控制线程(或可运行)的执行:

public class TestFtp extends Thread {
[...]
boolean abort;
public void run() {
    [...]
    do{
      [...]
    } while (this.continuous && !abort);
    if (abort){
      // You might want to do something here
    }else{
      // The stuff you normally do
    }
}
}

然后只需将abort标志设置为false从外部。这样,您可以更好地控制线程将如何终止,以及thread.interrupt();未定义的行为。

于 2012-04-20T11:20:09.227 回答
0

好吧,我很抱歉,但我承认我还没有阅读您的所有代码,但是如果您想中断正在运行的线程,请做两件事:

  1. 在 try/catch 块中运行线程代码,如下所示:

例子:

public void run() {
    try {
        // code to run
    } catch (InterruptedException ie) {
        // thread interrupted, may want to do some clean up
        // but must return as quickly as possible to avoid halting external code
    }
}
  1. 需要时在外部调用上面线程的interrupt()方法。

例子:

thread.interrupt();

这将告诉虚拟机在你的线程中抛出 InterruptedException,无论它在做什么,让你有机会做一些事情。

我希望这就是你要找的...

编辑

好的,一个有效的具体示例:

public class Driver {

private static int count = 0;

public static void main(String[] args) {

    Thread t = new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                bigTask();
            } catch (InterruptedException ie) {
                System.out.println("Interrupted thread! Count is " + count);
            }
        }
    });

    t.start();

    try {
        Thread.sleep(1000);
        System.out.println("Trying to interrupt thread");
        t.interrupt();
    } catch (InterruptedException e) {}

}

private static void bigTask() throws InterruptedException {
    List<BigDecimal> bigs = new ArrayList<BigDecimal>();
    for (int i = 0; i < 10000000; i++) {
        bigs.add(BigDecimal.valueOf(i));
        if (Thread.interrupted()) {
            throw new InterruptedException();
        }
        count = i;
    }
    System.out.println("Ok, added ten million items, count is " + count);
}

}

于 2012-04-20T09:34:52.153 回答