以异步方式实现长轮询
Posted
技术标签:
【中文标题】以异步方式实现长轮询【英文标题】:Implementing long polling in an asynchronous fashion 【发布时间】:2011-12-26 06:47:52 【问题描述】:是否可以从它的线程中取出一个 HTTPServletRequest,解散这个线程(即把它带回池中),但保持与浏览器的底层连接正常工作,直到我从一个耗时的操作中得到结果(比如说,处理图像)?处理返回数据时,应异步调用另一个方法,并将请求和数据作为参数。
通常,长池以相当阻塞的方式运行,当前线程不会被解散,这会降低服务器端应用程序在并发连接方面的可伸缩性。
【问题讨论】:
您是否尝试过 Servlet 3.0,它是异步 Servlet? download.oracle.com/javaee/6/api/javax/servlet/annotation/… 它将你的线程返回到池中,但允许处理一些长期操作并读取用户的请求 【参考方案1】:是的,你可以用 Servlet 3.0 做到这一点
以下是每 30 秒编写一次警报的示例(未测试)。
@WebServlet(async =“true”)
public class AsyncServlet extends HttpServlet
Timer timer = new Timer("ClientNotifier");
public void doGet(HttpServletRequest req, HttpServletResponse res)
AsyncContext aCtx = request.startAsync(req, res);
// Suspend request for 30 Secs
timer.schedule(new TimerTask(aCtx)
public void run()
try
//read unread alerts count
int unreadAlertCount = alertManager.getUnreadAlerts(username);
// write unread alerts count
response.write(unreadAlertCount);
catch(Exception e)
aCtx.complete();
, 30000);
以下是基于事件编写的示例。必须实现 alertManager,它会在需要提醒客户端时通知 AlertNotificationHandler。
@WebServlet(async=“true”)
public class AsyncServlet extends HttpServlet
public void doGet(HttpServletRequest req, HttpServletResponse res)
final AsyncContext asyncCtx = request.startAsync(req, res);
alertManager.register(new AlertNotificationHandler()
public void onNewAlert() // Notified on new alerts
try
int unreadAlertCount =
alertManager.getUnreadAlerts();
ServletResponse response = asyncCtx.getResponse();
writeResponse(response, unreadAlertCount);
// Write unread alerts count
catch (Exception ex)
asyncCtx.complete();
// Closes the response
);
【讨论】:
如果用户进入页面,并且创建了异步对象,但随后他们刷新了页面,会发生什么情况?是否创建了另一个对象?现在会发回两个请求吗?或者如果他们离开页面怎么办?响应会被发送到外太空吗?抱歉,我无法解决这个问题! 在您的第一个示例中,您在另一个方法 doGet() 中有一个方法 run()。这对我来说是新的。你必须这样做还是可以分开方法?而且一定要叫run吗?【参考方案2】:是的,可以使用 Servlet 规范版本。 3.0。我可以推荐的实现是 Jetty 服务器。见here。
【讨论】:
以上是关于以异步方式实现长轮询的主要内容,如果未能解决你的问题,请参考以下文章