以异步方式实现长轮询

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。

【讨论】:

以上是关于以异步方式实现长轮询的主要内容,如果未能解决你的问题,请参考以下文章

轮询长轮询comet长连接SSEwebsocket

轮询长轮询comet长连接SSEwebsocket

轮询长轮询长连接socket连接WebSocket

轮询长轮询长连接socket连接WebSocket

以异步方式实现长轮询

python之轮询长轮询websocket