Long Polling vs WebSocket in Go: Der Kampf um Echtzeit

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Einleitung: Das Dilemma des Entwicklers

\n\n

Stellen Sie sich vor: Sie schreiben einen Chat, einen Börsenterminal oder ein Online-Spiel in Go. Der Client muss Aktualisierungen sofort erhalten. Der gute alte AJAX mit periodischem Abfragen (Polling) fällt weg – zu viele nutzlose Anfragen, die sowohl den Server als auch den Akku des Benutzers belasten. Es bleiben zwei Kandidaten: Long Polling (langes Abfragen) und WebSocket.

\n\n

Beide lösen die Aufgabe der „Echtzeit“, tun dies jedoch auf grundlegend unterschiedliche Weise. Welche sollten Sie für Ihre Go-Anwendung wählen? Lassen Sie es uns ohne Umschweife klären, mit lebendigen Codebeispielen und einer ehrlichen Analyse der Vor- und Nachteile. Dieser Artikel ist Ihr Navigator in der Welt der Echtzeit-Kommunikation in Go.

\n\n

Was ist Long Polling in Go?

\n\n

Long Polling ist eine Weiterentwicklung des normalen Polling. Der Client sendet eine HTTP-Anfrage an den Server, aber der Server antwortet nicht sofort, wenn keine Daten vorliegen. Er „hängt“ (hält die Verbindung offen) und wartet, bis ein neues Ereignis eintritt. Sobald das Ereignis eintritt, sendet der Server eine Antwort und der Client erstellt sofort eine neue Long Polling-Anfrage. Der Zyklus wiederholt sich.

\n\n

In Go wird dies dank Goroutinen und Kanälen sehr elegant implementiert. Der Server kann den Anfragen-Handler „schlafen legen“, bis Daten verfügbar sind.

\n\n

Beispiel eines Long Polling-Servers in Go

\n\n
package main\n\nimport (\n    "fmt"\n    "net/http"\n    "time"\n)\n\n// Kanal, in den neue Nachrichten eingehen\nvar messages = make(chan string, 10)\n\nfunc longPollHandler(w http.ResponseWriter, r *http.Request) {\n    select {\n    case msg := <-messages:\n        fmt.Fprintf(w, "Neue Nachricht: %s", msg)\n    case <-time.After(30 * time.Second):\n        // Timeout – wenn 30 Sekunden lang keine Nachrichten eingehen\n        http.Error(w, "Timeout", http.StatusGatewayTimeout)\n    }\n}\n\nfunc main() {\n    // Goroutine, die das Eintreffen neuer Nachrichten simuliert\n    go func() {\n        for {\n            time.Sleep(5 * time.Second)\n            messages <- fmt.Sprintf("Zeit: %s", time.Now().String())\n        }\n    }()\n\n    http.HandleFunc("/poll", longPollHandler)\n    http.ListenAndServe(":8080", nil)\n}\n
\n\n

Der Client in JavaScript sieht so aus: Nach Erhalt der Antwort (oder eines Timeouts) ruft er sofort erneut /poll auf. Einfach, zuverlässig, funktioniert über alle Proxys und Firewalls hinweg.

\n\n

WebSocket in Go: Vollduplex

\n\n

WebSocket ist ein Protokoll, das nach dem Handshake (HTTP Upgrade) die Verbindung in einen permanenten bidirektionalen Kanal umwandelt. Der Server kann dem Client jederzeit Daten senden, und der Client dem Server. Keine wiederholten Anfragen, keine Timeouts.

\n\n

In Go hat die Standardbibliothek keine integrierte Unterstützung für WebSocket, aber es gibt den Goldstandard – das Paket gorilla/websocket. Es ist stabil, gut dokumentiert und wird in tausenden Projekten im Produktionseinsatz verwendet.

\n\n

Beispiel eines WebSocket-Servers in Go

\n\n
package main\n\nimport (\n    "log"\n    "net/http"\n    "time"\n\n    "github.com/gorilla/websocket"\n)\n\nvar upgrader = websocket.Upgrader{\n    CheckOrigin: func(r *http.Request) bool {\n        return true // Für die Entwicklung. In der Produktion prüfen!\n    },\n}\n\nfunc wsHandler(w http.ResponseWriter, r *http.Request) {\n    conn, err := upgrader.Upgrade(w, r, nil)\n    if err != nil {\n        log.Print("Upgrade fehlgeschlagen:", err)\n        return\n    }\n    defer conn.Close()\n\n    // Endlosschleife zum Lesen und Schreiben\n    for {\n        // Nachricht vom Client lesen\n        _, message, err := conn.ReadMessage()\n        if err != nil {\n            log.Println("Lesefehler:", err)\n            break\n        }\n        log.Printf("Empfangen: %s", message)\n\n        // Antwort senden (oder Push-Benachrichtigung)\n        err = conn.WriteMessage(websocket.TextMessage, []byte("Server: "+time.Now().String()))\n        if err != nil {\n            log.Println("Schreibfehler:", err)\n            break\n        }\n    }\n}\n\nfunc main() {\n    http.HandleFunc("/ws", wsHandler)\n    log.Pr                

Blogs

Buchempfehlungen