5

我试图使用 Servlet API 3 中定义的异步处理来实现 COMET 聊天。它不起作用 - 聊天被阻止,所以我创建了调试 servlet 来仅测试异步部分。

这是我的 doGet 方法:

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    log.debug("doGet called");
    int timeout = 30 + RandomUtils.nextInt(60);
    String message = RandomStringUtils.randomAlphanumeric(50 + RandomUtils.nextInt(250));
    response.setHeader("Access-Control-Allow-Origin", "*");
    final AsyncContext context = request.startAsync();

    synchronized(items) {
        items.add(new RequestItem(context, message, timeout));
    }
    log.debug("doGet created request and finished");
}

我将请求项目放入队列中,并且有一个线程正在运行,它将在指定超时后获取项目并将响应发送到 AsyncContext,打印有关它的消息。问题是,线程被阻塞,直到 AsyncContext 得到响应。这是在浏览器中请求 4 个页面加载后在我的日志中可见的内容:

2011-12-08 13:56:36,923 DEBUG [my.servlet.TestAsyncServlet] doGet called
2011-12-08 13:56:36,952 DEBUG [my.servlet.TestAsyncServlet] doGet created request and finished
2011-12-08 13:57:39,934 TRACE [my.servlet.TestAsyncServlet] respond on item RequestItem [context=org.apache.catalina.core.AsyncContextImpl@175870a, message=zEQpATavzwFl6qIbBKve4OzIY9UUuZBwbqN1TC5KpU3i8LM9B6ChgUqaRmcT2yF, timeout=0]
2011-12-08 13:57:39,962 DEBUG [my.servlet.TestAsyncServlet] doGet called
2011-12-08 13:57:39,962 DEBUG [my.servlet.TestAsyncServlet] doGet created request and finished
2011-12-08 13:58:53,949 TRACE [my.servlet.TestAsyncServlet] respond on item RequestItem [context=org.apache.catalina.core.AsyncContextImpl@88ee03, message=pKHKC632CPIk7hGLV0YqCbQl1qpWIoyNv5OWCp21bEqoni1gbY79HT61QEUS2eCjeTMoNEwdqKzCZNGgDngULysSzVdzFTnQQ5cQ8JvcYnp1pLVqGTueJPWnbRdUuO, timeout=0]
2011-12-08 13:58:53,960 DEBUG [my.servlet.TestAsyncServlet] doGet called
2011-12-08 13:58:53,960 DEBUG [my.servlet.TestAsyncServlet] doGet created request and finished
2011-12-08 13:59:36,954 TRACE [my.servlet.TestAsyncServlet] respond on item RequestItem [context=org.apache.catalina.core.AsyncContextImpl@197950e, message=43FPeEUZWBLqgkAqS3WOFMiHUMVvx6o4jNqWLx8kUvwxqJqpOZyGCtiIcr7yw, timeout=0]
2011-12-08 13:59:36,999 DEBUG [my.servlet.TestAsyncServlet] doGet called
2011-12-08 13:59:36,999 DEBUG [my.servlet.TestAsyncServlet] doGet created request and finished
2011-12-08 14:00:34,957 TRACE [my.servlet.TestAsyncServlet] respond on item RequestItem [context=org.apache.catalina.core.AsyncContextImpl@1cb1278, message=r69Y4NQsyR1vj0kzUlHssic2x1Yrr6T09IGKjWAH1E6Lz4VhFTy9dQHi5CPeTObyjLLBDlCLEDfiyMUnVkVIEgYG7r47Ak4w30RklhzdEi9nthqdfNkry6nyjircsFPX534NqWjI1LwsrGq5nOa3ZYtfjfPVpGlk4KDmWP11L53YntO3GmptZPKa50gcqj9i, timeout=0]

正如所见,下一个 doGet 方法仅在前一个请求(理论上是异步的)应答后才被调用。所以整个异步事情根本不起作用!这是 web.xml 声明:

  <servlet>
    <servlet-name>TestAsyncServlet</servlet-name>
    <servlet-class>my.servlet.TestAsyncServlet</servlet-class>
    <async-supported>true</async-supported>
  </servlet>
  <servlet-mapping>
    <servlet-name>TestAsyncServlet</servlet-name>
    <url-pattern>/test-async</url-pattern>
  </servlet-mapping>

我正在尽一切可能在互联网上找到。我看不出犯错的地方。我发现在 servlet.xml 中配置没有什么特别之处。所以问题是,为什么它不能正常工作?

4

2 回答 2

5

OK, as the part of the research I've written testing programm that opened multiply connections to tomcat and did GET/POST on the async servlet. I've debugged and rechecked my server.xml configuration, limited thread pool for better visibility of test results etc. Now my configuration of connector looks like that:

<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol" 
               minProcessors="3"
               maxProcessors="8"
               maxThreads="20"
               connectionTimeout="150000" 
               asyncTimeout="150000" />

And this is working! I've made test using NIO and made 1000 connections at one time, and all of them got processed in one time.

However, the effect I've described, still exists in browser. When I try to load servlet on 10 tabs, first get loaded, than second etc. It seems to be browser's behaviour, nothing gets blocked on server. When I opened 3 browsers (Firefox, Chrome, Opera) I've got 3 connections processed on one time.

So, the asynchronous processing defined in Servlet API 3.0 works on Tomcat 7, however, it must be tested with own programm not with multiple tabs in browser... testing COMET chat in multiple tabs can also not work as expected. However, in real-life example one computer will open only one connection. And, the browser's behaviour is not any server's fault.

edit After Spring MVC solution was included into web application, async processing mode was stopped (parameter from web.xml was ignored). However, the async support can be set up manually via adding line:

request.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", true);
于 2011-12-09T13:57:11.507 回答
1

我认为您的服务器配置正确。如果您只是使用浏览器加载,那么问题可能出在浏览器的工作方式上。如果您只是使用浏览器访问网页,那么浏览器将尝试加载整个页面并阻止,直到完成。在异步请求完成之前,您的浏览器不会完成加载。

For example, if you were to look at the messaging with a tool like Fiddler I'd expect you'd see the following (assuming delay is 4):

Browser -> Server [Time: 0]   Request
Server -> Browser [Time: 0.1] Async Response
Server -> Browser [Timer: 4]  Complete Response
Browser shows page loaded.

If you took out the async mode you'd see:

Browser -> Server [Time: 0] Request
Server -> Browser [Time: 4] Response
Browser shows page loaded.

In both examples the page won't be fully loaded until the whole request is finished, even though one is asynchronous and one is synchronous. To fully take advantage of asynchronous requests you're going to need a smarter client, e.g. Javascript or flex or something.

In other words, I don't think you can say the server is correct or not by just loading with the browser. I would grab a tool like Fiddler and see exactly what HTTP messages are going across.

于 2011-12-08T14:24:28.850 回答