【问题标题】:Long polling Kill threads on server side长轮询杀死服务器端的线程
【发布时间】:2015-03-30 06:40:46
【问题描述】:

早安/晚安,

我正在通过 ajax-java 实现客户端-服务器之间的长池。并且长轮询在客户端正常工作,每 30 秒抛出一个新连接,前一个连接被中止。但问题是,在服务器端,所有这些请求/线程都保持活动状态,直到我们有一些东西要返回给客户端。但就像我说的客户可能不再听了。这里有一些代码:

客户:

     // Long Polling (Recommened Technique - Creates An Open  Connection To Server ∴ Fast)
  (function poll(){
    var tenantName = $("#tenantName").val();
    $.ajax({
    method:"GET",
    url: "url",
    success: function(data){
        if (data === true) {
            bootbox.alert("Page has been modify <a href='javascript:void(0)' onclick='reload()'>reload</a>");
        }
     }, dataType: "json", complete: poll, timeout: 60000 });
})();

服务器:

       /**
 * @return
 */
@RequestMapping(method = RequestMethod.GET)
@ResponseBody
public Boolean getSubStepStatus(@RequestParam("subStep") String subStep,
                                @RequestParam("tenantId") String tenantId) {
    if (!isInStep(subStep, tenantId)) {
        tenantsInStep.get(subStep).add(tenantId);
    }
    while (true) {
        String modifierTenantId = stepModifyByTenant.get(subStep);
        if (modifierTenantId != null && !modifierTenantId.equals(tenantId) && !isInStep(subStep, tenantId)) {
            tenantsInStep.get(subStep).remove(tenantId);
            return true;
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

问题就像我说的所有线程每 30 秒在服务器端增长和增长,我在使用这种技术时做错了什么?

【问题讨论】:

    标签: java spring jakarta-ee


    【解决方案1】:
    Thread.sleep(1000);
    

    不是在 Java 中进行长轮询的方法。方法是把请求踢到异步模式,注册一个监听器,然后放弃工作线程。

    【讨论】:

    • 请求是异步的。如果您建议释放请求线程并将其发送回客户端,您如何避免客户端发送另一个请求。长轮询的概念是保持请求通道打开,直到有需要通知的内容或超时通过。
    • 不,仅仅因为您从 AJAX 发出请求并没有将 servlet 请求置于异步模式,您必须实际调用 ServletRequest.html#startAsync。不,我不建议释放请求线程并向客户端发送响应。我确实建议释放请求线程,将其置于异步模式并注册一个侦听器,这是在 Java 中实现服务器端推送的正确方法。
    【解决方案2】:

    您似乎在使用 SpringMVC,我假设 Web 应用程序在 servlet 引擎(例如 Tomcat 或 Jetty)中运行。

    在处理请求时,服务器无法检测客户端是否仍在侦听,除非它正在尝试发送响应数据(see also this question)。您的控制器代码执行一个可能的无限循环(这本身就是一个坏主意)。只要这个循环在运行,就不会发送任何响应数据,因此控制器会继续循环,即使客户端已经断开连接。

    如果您想保留当前设计,一个简单的解决方法是防止无限循环,即在设定的迭代次数或经过的时间后中断并发送false 作为响应。然后客户端必须重新连接才能开始新的轮询周期。

    【讨论】:

    • 客户端,中止请求并每 30 秒创建一个新请求。问题是服务器保留旧请求,直到有什么要说的。正如我在所有教程中阅读的那样,我只是在遵循长轮询技术。
    • 正如我在回答中所说,服务器无法检测到客户端中止请求,直到它实际尝试向客户端发送数据。只要请求处理线程被困在循环中,它就不会尝试向客户端发送数据,因此请求线程只会继续运行,直到它可以退出循环,尝试向客户端发送true,然后才意识到客户端已断开连接。
    • 很难相信 httpServletResponse 没有像 isRequestAlive 或类似的布尔方法
    • 那就自己看吧:HttpServletResponseHttpServletRequest。 spring 团队还有一篇关于使用 mvc here 进行长轮询的博文,可能对您有所帮助。
    • 我已经这样做了,这就是我抱怨的原因。可能还不够清楚XD。感谢春季博客
    猜你喜欢
    • 2017-01-22
    • 2021-03-12
    • 1970-01-01
    • 2019-10-12
    • 1970-01-01
    • 2013-05-25
    • 2020-08-12
    • 2012-07-03
    • 1970-01-01
    相关资源
    最近更新 更多