Long Polling vs WebSocket in Java: Duell der Echtzeit-Technologien
\n\nStellen Sie sich vor: Sie entwickeln einen Chat, einen Börsenterminal oder ein Online-Spiel in Java. Der Benutzer wartet auf Updates, aber der Server schweigt. Wie bringen Sie Daten dazu, sofort anzukommen? Früher gab es nur einen Ausweg — Long Polling. Heute betritt WebSocket die Arena. Aber wer gewinnt im echten Kampf?
\n\nIn diesem Artikel vergleichen wir nicht nur die Konzepte. Wir schreiben Live-Code in Java, werfen einen Blick in das Innenleben beider Technologien und entscheiden, was Sie in Ihrem nächsten Projekt verwenden sollten. Willkommen im Ring!
\n\nWas ist Long Polling (und warum ist es kein „Polling“)?
\n\nKlassisches HTTP ist wie ein Brief: Anfrage senden → Antwort erhalten. Wenn der Server nichts zu sagen hat, gibt er eine leere Antwort zurück. Der Client muss alle N Sekunden erneut fragen. Das ist Short Polling — eine Sackgasse.
\n\nLong Polling arbeitet raffinierter. Der Client sendet eine Anfrage, und der Server… schläft ein. Er hält die Verbindung offen, bis ein neues Ereignis eintritt (oder ein Timeout abläuft). Sobald das Ereignis eintritt, wacht der Server auf und sendet die Antwort. Der Client erstellt sofort eine neue Long Polling-Anfrage. Der Kreislauf schließt sich.
\n\nLong Polling in Java: Einfache Implementierung
\n\nStellen wir uns vor, wir schreiben einen Benachrichtigungsserver mit reinem Servlet API (ohne Spring, zur besseren Verständlichkeit). Für Long Polling benötigen wir asynchrone Verarbeitung (AsyncContext), sonst blockiert der Server alle Threads.
\n\nimport 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 // Warteschlange für "schlafende" Verbindungen\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); // Timeout 30 Sekunden\n\n // Kontext speichern\n WAITING_CLIENTS.add(asyncContext);\n\n // Wenn Timeout abläuft, leere Antwort zurückgeben\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 // Andere Listener-Methoden aus Gründen der Kürze weggelassen\n });\n }\n\n // Diese Methode wird aufgerufen, wenn ein neues Ereignis eintritt\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\nSo funktioniert es:
\n- \n
- Der Client sendet eine GET-Anfrage an
/long-poll. \n - Der Server versetzt die Anfrage in den asynchronen Modus und „schläft ein“ (wartet). \n
- Wenn eine Nachricht eintrifft (Methode
sendEventToClient), wird die Antwort gesendet und die Verbindung geschlossen. \n