使用HTTP长轮询来实现Comet
环境
- java
- tomcat7及以上
- servlet 3.0
服务器端
Servlet 3.0 之前,一个普通 Servlet 的主要工作流程大致如下:首先,Servlet 接收到请求之后,可能需要对请求携带的数据进行一些预处理;接着,调用业务接口的某些方法,以完成业务处理;最后,根据处理的结果提交响应,Servlet 线程结束。而Servlet 3.0 支持异步处理:首先,Servlet 接收到请求之后,可以将请求转交给一个异步线程来执行业务处理,线程本身返回至容器,此时 Servlet 还没有生成响应数据,异步线程处理完业务以后,可以直接生成响应数据(异步线程拥有 ServletRequest 和 ServletResponse 对象的引用),或者将请求继续转发给其它 Servlet。如此一来, Servlet 线程不再是一直处于阻塞状态以等待业务逻辑的处理,而是启动异步线程之后可以立即返回。 默认情况下,Servlet 和过滤器并没有开启异步处理特性,如果希望使用该特性,则必须按照如下的方式启用:
对于使用传统的部署描述文件 (web.xml) 配置 Servlet 和过滤器的情况,Servlet 3.0 为
和 标签增加了 子标签,该标签的默认取值为 false,要启用异步处理支持,则将其设为 true 即可。 1
2
3
4
5
6
7
8<servlet>
<servlet-name>msgPush</servlet-name>
<servlet-class>com.servlet.MsgPushServlet</servlet-class>
<async-supported>true</async-supported>
</servlet>
<filter>
<async-supported>true</async-supported>
</filter>对于使用 Servlet 3.0 提供的 @WebServlet 和 @WebFilter 进行 Servlet 或过滤器配置的情况,这两个注解都提供了 asyncSupported 属性,默认该属性的取值为 false,要启用异步处理支持,只需将该属性设置为 true 即可。
servlet示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47public final class MsgPushServlet extends HttpServlet {
private final Queue<AsyncContext> asyncContexts = new ConcurrentLinkedQueue<AsyncContext>();
private final Random random = new Random();
private final Thread generator = new Thread("Event generator") {
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
Thread.sleep(random.nextInt(5000)); //睡眠一段时间
while (!asyncContexts.isEmpty()) { //对队列中的异步请求进行处理
AsyncContext asyncContext = asyncContexts.poll();
HttpServletResponse peer = (HttpServletResponse) asyncContext.getResponse();
peer.getWriter().write(new JSONArray().put("At " + new Date()).toString());
peer.setStatus(HttpServletResponse.SC_OK);
peer.setContentType("application/json");
asyncContext.complete();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}
};
public void init() throws ServletException {
generator.start();
}
public void destroy() {
generator.interrupt();
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
AsyncContext asyncContext = req.startAsync();
asyncContext.setTimeout(0);
asyncContexts.offer(asyncContext);
}
}
客户端
1 | function long_polling() { |