【问题标题】:Tomcat 7 Servlet spawning a threadTomcat 7 Servlet 产生一个线程
【发布时间】:2014-11-13 22:21:42
【问题描述】:

我正在编写一个网络应用程序,我想用它来执行 FTP 任务(下载)

我在 Tomcat 中安装了 Apache FTPS 服务器和一个准备启动传输的 Java 客户端。

客户端将被 Servlet 调用。

例如:

http://laptop:8080/MyServlet?action=download&from=desktop&file=C:/home/fred/file.xml 

会告诉我的 laptop 上的实例从我的 desktop 下载 file.xml

编辑: 抱歉,我从来没有说得很清楚。

这个过程的两端都会有一个 FTP 服务器。 1 在我的远程笔记本电脑上,1 在我的本地桌面上。所以简而言之,我正在向远程端的 Servlet 提交一个 FTP 'get' 请求。然后 Servlet 启动一个 FTP 进程来拉取文件。

我的 Servlet 已全部设置为接收 GET 参数并完成工作。

如果文件很大,那么每个请求都需要很长时间才能完成。我希望尽快释放 Servlet 资源。

理想情况下,我希望发生以下事情:

  1. 用户向 Servlet 发送 URL
  2. Servlet 消化 URL 并计算出什么文件和来自哪里等等......
  3. Servlet 将信息传递给线程
  4. Servlet 返回“进行中”消息
  5. 请求完成
  6. 线程仍在后台下载文件

此时我不太关心 Servlet 是否知道线程是否成功,我只需要它启动一个并忘记它。 FTP 进程将在其他地方单独记录任何问题。

我对在 WebApp 中创建 Threadpool 并从那里获取线程的概念很感兴趣,但是我发现的所有示例都是旧的,并不能真正满足我的理解水平。

StackOverflow 上有一些类似的问题,这与我所要求的最相似,但它只是暗示了一些我事先不知道的 ExecutorService。我将如何在 WebApp 中进行设置? What is recommended way for spawning threads from a servlet in Tomcat

有关信息, 我对此进行了研究,并发现了许多不完整的示例,这些示例需要比我目前更好的理解,或者提示需要什么。 我读过的很多例子都是几年前的,不是最近的。我希望可能有一个神奇的单线来做我需要的一切(怀疑),这在过去一年左右出现了:) 我是 Java 中的线程概念的新手,我总体上了解线程,因此感谢您为我提供的任何帮助。

特雷弗

【问题讨论】:

  • 你想使用标题中所说的HTTP协议(你所描述的)还是FTP协议(不同的协议和不同的端口)?
  • 你好 Serge,我想使用 HTTP 来请求 8080 端口上的 Servlet,然后触发一个 FTP 进程,下载端口 21 上的文件。

标签: java multithreading tomcat servlets threadpool


【解决方案1】:

我不确定我是否真的明白你想要什么......

client                                      server
send request (via HTTP) and wait for
         HTTP response
                                            analyse request and find file to send
                                            ... (processing)
                                            send HTTP response (1) with ?
opens FTP connection (could not open it before)
                                            receive FTP request (command connection)
                                            send file (data connection)
file is received and saved locally

如果客户端是浏览器,响应 (1) 应该足以重定向到像 ftp://host/path/to/file 这样的 URL,因为所有主要浏览器都知道 FTP 协议并能够使用它来下载一个文件。

问题不在服务器端,您可以轻松地生成一个可以充当 FTP 客户端或(可能更难)充当 FTP 服务器的线程,但我无法想象比客户端重定向更好:客户端已打开HTTP 连接不能用于 FTP 传输,它必须为 FTP 请求打开一个新连接。由于它是一个新连接,您希望上一步启动的线程如何处理它? FTP 中没有会话的概念,也没有简单的方法来识别正确的请求。

根据评论编辑:

好的,我似乎只想在请求完成后在服务器上进行延迟处理。你有两种方法:

  • 按照标签的建议,使用工作线程来完成这项工作。您的 servlet 是纯 Java,您可以像在任何其他 Java 应用程序中一样创建线程。如果您有兴趣稍后获得延迟处理的结果,您可以将会话(或简单地会话属性)引用到能够放置其进度和/或完成状态的线程。这需要更多样板代码,但保证可以正常工作(示例如下)
  • 您可以在 servlet 返回之前关闭 HTTP 连接。官方 servlet 规范并没有明确保证它,但我发现它至少在 tomcat 7 中可以工作。您可以在其他帖子Servlet - close connection but not method 上找到更多详细信息

使用简单线程的示例,并在会话中存储状态:

public class ThreadedServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest hsr, HttpServletResponse hsr1) throws ServletException, IOException {
        String fileName = null;
        // preliminary work ...
        Worker worker = new Worker(fileName);
        final HttpSession session = hsr.getSession();
        synchronized (session) {
            List<Status> statuses = (List<Status>) session.getAttribute("statuses");
            if (statuses == null) {
                statuses = new ArrayList<Status>();
            }
            statuses.add(new Status(fileName));
        }
        Thread thr = new Thread(worker);
        thr.start();
        // write the response either directly or by forwarding to a JSP
    }

    public static class Status implements Serializable {
        private String fileName;
        private WStatus status;

        public Status(String fileName) {
            this.fileName = fileName;
        }

        public String getFileName() {
            return fileName;
        }

        public void setFileName(String fileName) {
            this.fileName = fileName;
        }

        public WStatus getStatus() {
            return status;
        }

        public void setStatus(WStatus status) {
            this.status = status;
        }
    }

    public enum WStatus {
        STARTED,
        RUNNING,
        COMPLETED
    }

    private static class Worker implements Runnable {

        private String fileName;
        private Status status;

        public Worker(String fileName) {
            this.fileName = fileName;
        }

        @Override
        public void run() {
            status.setStatus(WStatus.RUNNING);
            // do your stuff ...
            status.setStatus(WStatus.COMPLETED);
        }
    }
}

【讨论】:

  • 考虑它的基本元素(暂时忘记 FTP 任务) 在使用浏览器的本地客户端上...我想连接到远程 Servlet。我希望那个 Servlet 在远程机器上生成一个线程来做一些工作。虽然这项工作正在进行中,但我希望 Servlet 报告 200(或任何数字),这就是它的工作已完成 Servlet 可以完成工作,但我希望它传递给工作线程,以便应用程序不会挂起.
  • 我现在对主要问题进行了编辑,以解释在两端(客户端和服务器)上将运行一个 FTP 进程。 servlet 被要求从我的本地客户端下载/获取文件。此应用程序中没有文件推送。道歉。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多