Long Polling 与 WebSocket 在 Java 中的对决:实时技术如何选择?

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

Long Polling 与 WebSocket 在 Java 中的对决:实时技术的较量

\n\n

想象一下:您正在用 Java 开发一个聊天应用、股票交易终端或在线游戏。用户等待更新,而服务器却沉默不语。如何让数据瞬间到达?过去只有一种方法——Long Polling。如今,WebSocket 登上了舞台。但在这场实战对决中,谁会胜出?

\n\n

本文不仅会对比概念。我们将编写真实的 Java 代码,深入探究这两种技术的内部机制,并决定在您的下一个项目中该使用哪一种。欢迎来到擂台!

\n\n

什么是 Long Polling(以及为什么它不是“轮询”)?

\n\n

传统的 HTTP 就像一封信:发送请求 → 收到响应。如果服务器无话可说,它会返回一个空响应。客户端不得不每隔 N 秒再次询问。这就是 Short Polling——一条死胡同。

\n\n

Long Polling 则更加巧妙。客户端发送请求,而服务器……进入休眠。它保持连接打开,直到有新事件发生(或超时)。一旦事件发生,服务器就会唤醒并发送响应。客户端立即创建一个新的 Long Polling 请求。循环就此闭合。

\n\n

Java 中的 Long Polling:简单实现

\n\n

假设我们使用纯 Servlet API(不使用 Spring,以便更清晰)编写一个通知服务器。对于 Long Polling,我们需要异步处理(AsyncContext),否则服务器会阻塞所有线程。

\n\n
import javax.servlet.AsyncContext;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\nimport java.util.Queue;\nimport java.util.concurrent.ConcurrentLinkedQueue;\n\n@WebServlet(urlPatterns = "/long-poll", asyncSupported = true)\npublic class LongPollingServlet extends HttpServlet {\n\n    // 用于存储“休眠”连接的队列\n    private static final Queue<AsyncContext> WAITING_CLIENTS = new ConcurrentLinkedQueue<>();\n\n    @Override\n    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {\n        AsyncContext asyncContext = req.startAsync();\n        asyncContext.setTimeout(30_000); // 超时时间 30 秒\n\n        // 保存上下文\n        WAITING_CLIENTS.add(asyncContext);\n\n        // 如果超时,返回空响应\n        asyncContext.addListener(new javax.servlet.AsyncListener() {\n            public void onTimeout(javax.servlet.AsyncEvent event) {\n                WAITING_CLIENTS.remove(asyncContext);\n                try {\n                    HttpServletResponse response = (HttpServletResponse) event.getAsyncContext().getResponse();\n                    response.getWriter().write("timeout");\n                    response.setStatus(HttpServletResponse.SC_OK);\n                    asyncContext.complete();\n                } catch (IOException e) { e.printStackTrace(); }\n            }\n            // 其他监听器方法已省略以保持简洁\n        });\n    }\n\n    // 当新事件出现时调用此方法\n    public static void sendEventToClients(String message) {\n        for (AsyncContext ctx : WAITING_CLIENTS) {\n            try {\n                HttpServletResponse response = (HttpServletResponse) ctx.getResponse();\n                response.getWriter().write(message);\n                response.setStatus(HttpServletResponse.SC_OK);\n                ctx.complete();\n                WAITING_CLIENTS.remove(ctx);\n            } catch (IOException e) { e.printStackTrace(); }\n        }\n    }\n}
\n\n

工作原理:

\n
    \n
  • 客户端向 /long-poll 发起 GET 请求。
  • \n
  • 服务器将请求转为异步模式并“休眠”(等待)。
  • \n
  • 当有消息出现时(通过 sendEventToClien

博客

书籍推荐