WebSockets sind ein Kommunikationsprotokoll, das die Echtzeitkommunikation zwischen Client und Server ermöglicht. WebSockets halten die Verbindung aufrecht und ermöglichen eine bidirektionale Kommunikation. Dadurch eignen sich WebSockets für Chat- und Börsenanwendungen, Multiplayer-Spiele und Tools für die Zusammenarbeit.
In diesem Artikel erfahren Sie, wie das WebSocket-Protokoll funktioniert und welche Vorteile es gegenüber HTTP hat. Außerdem zeigen wir Ihnen, wie Sie eine einfache Chat-Anwendung mit WebSockets im Frontend und Backend erstellen können.
HTTP wird häufig für die Interaktion zwischen Server und Client verwendet. Es funktioniert gut beim Abrufen von Daten und Erstellen von Ressourcen. Es ist jedoch unidirektional, d. h. der Client muss alle Anfragen initiieren, und der Server kann keine Daten von sich aus senden. Diese Einschränkung macht es ineffizient für Anwendungen wie Börsenticker oder Multiplayer-Spiele, bei denen Aktualisierungen zwischen Client und Server Hunderte oder Tausende von Malen pro Minute übertragen werden müssen. Für jede Aktualisierung muss der Client einen Anfrage-Antwort-Zyklus wiederholen, was eine Menge an Rechenressourcen und Bandbreite beansprucht. Die Verwendung von HTTP für solche Anwendungen macht den Server außerdem ineffizient, da er mit neuen Anfragen überlastet wird, selbst wenn keine Aktualisierung für die Clients verfügbar ist.
Um diese Einschränkung zu beheben, können Sie HTTP Long Polling ausprobieren, bei dem der Server die Verbindung länger offen hält und darauf wartet, weitere Daten mit der Antwort zu senden. Sobald der Client die Antwort erhält, stellt er eine neue Anfrage, um weitere Daten anzufordern. Während dies gut funktioniert, um das Echtzeitverhalten zu replizieren, kann das Offenhalten einer langen Verbindung zu Timeout-Problemen beim Server führen und die Leistung beeinträchtigen, wenn zu viele Clients den Server abfragen, auch wenn keine neuen Updates verfügbar sind. Da der Client außerdem in vordefinierten Intervallen Anfragen stellt, erscheinen die Aktualisierungen möglicherweise nicht sofort. Stellen Sie sich zum Beispiel ein Multiplayer-Videospiel vor, bei dem die Standorte und Spielstände der Spieler in Echtzeit synchronisiert werden müssen. HTTP müsste alle paar Sekunden eine neue Anfrage senden, um den neuesten Spielstand abzurufen, was zu unnötigem Netzwerk-Overhead und Latenzzeiten führt.
Andererseits bieten WebSockets eine viel geringere Latenzzeit und einen geringeren Netzwerk-Overhead, während ein bidirektionaler Kanal für die Echtzeitkommunikation erhalten bleibt. Die Verwendung einer Vollduplex-Verbindung ermöglicht es dem Client und dem Server, zu interagieren und Nachrichten zu senden, ohne eine neue Verbindung aufzubauen, was den Übertragungs-Overhead reduziert, der durch den Aufbau einer neuen Verbindung für jede Anfrage entsteht. Die dauerhafte Verbindung in WebSockets minimiert die Bandbreitennutzung, da die HTTP-Header nicht mit jeder Nachricht gesendet werden. WebSockets bieten auch ein Echtzeitgefühl für Anwendungen, da sie keinem Polling-Zyklus folgen müssen. Neue Daten kommen also sofort an, sobald sie verfügbar sind. All diese Vorteile machen WebSockets zu einer viel praktischeren Option für Echtzeitanwendungen, wie Chat- und Börsenanwendungen, Multiplayer-Spiele und Tools für die Zusammenarbeit.
Das folgende Diagramm vergleicht die Zeitachse von HTTP- und WebSockets-Verbindungen:
Wenn Sie schon einmal eine Chat-Funktion mit HTTP-Polling entwickelt haben, kennen Sie das Problem: Benutzer beschweren sich über verzögerte Nachrichten, die Server stöhnen unter den ständigen Anfragen, und Sie haben das ungute Gefühl, dass Ihre "Echtzeit"-Anwendung eine Verzögerung von 5 Sekunden hat. WebSockets lösen dieses Problem auf elegante Weise, indem sie eine dauerhafte, bidirektionale Verbindung aufrechterhalten, die sich wirklich sofort anfühlt.
Das WebSocket-Protokoll stellt eine dauerhafte Verbindung zwischen dem Client und dem Server für die bidirektionale Kommunikation her. Der Verbindungsprozess beginnt mit einer HTTP-Anforderung, dem so genannten Handshake, bei dem der Client den Server auffordert, die Verbindung auf das WebSocket-Protokoll umzustellen. Nach dem Handshake wird die Verbindung auf das WebSocket-Protokoll umgestellt. Das folgende Diagramm zeigt die Verbindungssequenz zwischen dem Client und dem Server.
So funktioniert die Verbindung über das WebSocket-Protokoll: Der Client sendet eine HTTP-Anfrage an den Server für ein Verbindungsupgrade auf das WebSocket-Protokoll. Die Anfrage enthält die Header Upgrade: websocket
und Connection:
Upgrade
-Header, wie im folgenden Beispiel:
GET /chat HTTP/1.1
Host: example.com:8000
Upgrade: websocket
Connection: Upgrade
Der Server sendet eine Antwort an den Client mit dem Statuscode 101
, um anzuzeigen, dass die Verbindung auf das WebSocket-Protokoll umgestellt wurde. Die Antwort enthält die Header Upgrade: websocket
und Connection: Upgrade
-Header. Hier ist ein Beispiel:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Nach dem Handshake können der Client und der Server nun ohne weitere Anfragen bidirektional kommunizieren.
Sowohl der Client als auch der Server können die Verbindung jederzeit schließen.
Als Nächstes zeigen wir Ihnen, wie Sie eine einfache Chat-Anwendung mit WebSockets erstellen, mit der Sie Nachrichten senden und empfangen können. Mit der Frontend-Anwendung können die Benutzer Nachrichten senden, und der Backend-Server sendet die Nachrichten an alle verbundenen Clients.
Sie können mit diesem GitHub-Repository mitmachen.
Um zu beginnen, erstellen Sie einen Projektordner mit dem Namen websockets-js-node
in Ihrem Arbeitsverzeichnis, indem Sie mkdir websockets-js-node
in Ihrem Kommandozeilenprogramm ausführen.
Erstellen Sie im Projektordner ein Verzeichnis namens frontend
, indem Sie mkdir frontend
in Ihrem Kommandozeilentool ausführen.
Erstellen Sie im Verzeichnis frontend
eine Datei mit dem Namen index.html
, indem Sie in Ihrem Kommandozeilenprogramm touch index.html
ausführen.
Fügen Sie in die Datei index.html
den Code für eine einfache HTML-Seite mit Eingabefeldern für den Benutzernamen und die Nachricht, eine Schaltfläche zum Senden der Nachricht und ein script
-Tag ein, um die Skriptdatei index.js
einzubinden, die die WebSocket-Logik des Frontends implementiert, wie folgt:
<!-- frontend/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>WebSocket Client</title>
</head>
<body>
<h1>WebSocket Client</h1>
<input type="text" id="username" placeholder="Your username" />
<input type="text" id="messageInput" placeholder="Type your message" />
<button onclick="sendMessage()">Send</button>
<div id="messages"></div>
<script src="index.js"></script>
</body>
</html>
Erstellen Sie eine Datei namens index.js
, indem Sie touch index.js
in Ihrem Befehlszeilentool ausführen, und fügen Sie den folgenden Code hinzu, um die WebSocket-Verbindung zum Backend-Server zu konfigurieren:
// frontend/script.js
// Create a WebSocket connection to the server
const socket = new WebSocket("ws://localhost:8080");
// Display connection status
socket.onopen = () => {
console.log("Connected to the WebSocket server");
};
// Handle incoming messages from the server
socket.onmessage = (event) => {
const messageDiv = document.getElementById("messages");
const newMessage = document.createElement("p");
newMessage.textContent = event.data.toString();
messageDiv.appendChild(newMessage);
};
// Handle connection closure
socket.onclose = () => {
console.log("Disconnected from the WebSocket server");
};
// Send a message to the server
function sendMessage() {
const usernameInput = document.getElementById("username");
const messageInput = document.getElementById("messageInput");
const message = messageInput.value;
const username = usernameInput.value;
if (message) {
socket.send(`${username}: ${message}`);
messageInput.value = "";
}
}
Der Code tut Folgendes:
socket.onopen
wird ausgelöst, wenn die Verbindung hergestellt ist.socket.onmessage
wird ausgelöst, wenn eine Nachricht vom Server empfangen wird. Es fügt die Nachricht an das Nachrichten
-Div an.socket.onclose
wird ausgelöst, wenn die Verbindung geschlossen wird.sendMessage
wird aufgerufen, wenn der Benutzer auf die Schaltfläche Senden klickt. Sie holt den Benutzernamen und die Nachricht aus den Eingabefeldern und sendet sie mit der Methode socket.send
an den Server.
Nun, da das Frontend fertig ist, wollen wir einen Backend-Server erstellen, mit dem sich das Frontend verbinden kann, um Nachrichten zu senden und zu empfangen. Im folgenden Abschnitt wird erklärt, wie man eine einfache Chat-Anwendung implementiert, die eingehende Nachrichten an alle verbundenen Clients sendet.
Für die Backend-Implementierung wird in diesem Beispiel das npm-Paket ws verwendet, das eine bewährte Bibliothek zur Erstellung eines WebSocket-Servers in Node.js darstellt.
Beachten Sie, dass die Codebeispiele in diesem Tutorial mit Node.js Version 20 erstellt wurden.
Erstellen Sie im Projektordner ein neues Verzeichnis namens backend
, indem Sie mkdir backend
in Ihrem Kommandozeilenprogramm ausführen. Erstellen Sie im backend
-Verzeichnis eine Datei namens server.js
, indem Sie in Ihrem Kommandozeilenprogramm touch server.js
ausführen.
Führen Sie den folgenden Befehl in Ihrem Befehlszeilenprogramm aus, um das ws-Paket
zu installieren:
npm install ws
Fügen Sie in der Datei server.js
den folgenden Code ein, um einen einfachen HTTP-Server und einen WebSocket-Server zu erstellen, der den HTTP-Server verwendet:
// backend/server.js
const http = require("http");
const { WebSocketServer } = require("ws");
// Create a simple HTTP server
const server = http.createServer((req, res) => {
res.writeHead(200, { "Content-Type": "text/plain" });
res.end("WebSocket server is running.\n");
});
// Create a WebSocket server using the HTTP server
const wss = new WebSocketServer({ server });
wss.on("connection", (ws) => {
console.log("New client connected");
// Send a welcome message to the newly connected client
ws.send("Server: Welcome to the WebSocket server!");
// Listen for messages from the client
ws.on("message", (message) => {
// Broadcast the received message to all connected clients
wss.clients.forEach((client) => {
if (client.readyState === ws.OPEN) {
client.send(message.toString());
}
});
});
// Handle client disconnection
ws.on("close", () => {
console.log("Client disconnected");
});
});
// Start the HTTP and WebSocket server on port 8080
server.listen(8080, () => {
console.log("Server is running on http://localhost:8080");
});
Der Servercode führt Folgendes aus:
on("connection")
wird ausgelöst, wenn sich ein neuer Client mit dem WebSocket-Server verbindet. Der Server sendet eine Willkommensnachricht an den neu verbundenen Client und beginnt, auf Nachrichten vom Client zu warten.on("message")
wird ausgelöst, wenn eine Nachricht von einem Client empfangen wird, und die Nachricht wird an alle verbundenen Clients gesendet.on("close")
wird ausgelöst, wenn ein Client die Verbindung mit dem WebSocket-Server trennt.server.listen()
wird verwendet, um den HTTP- und WebSocket-Server auf Port 8080 zu starten.Um den Server zu starten, navigieren Sie zum backend
-Verzeichnis und führen Sie node server.js
in Ihrem Befehlszeilentool aus. Dies startet den Server und macht ihn für die Frontend-Anwendung unter http://localhost:8080
zugänglich .
Öffnen Sie die Datei frontend/index.html
in zwei Webbrowser-Tabs, um die Echtzeit-Chat-Anwendung zu testen. Geben Sie die Benutzernamen ein und senden Sie Nachrichten von einer Registerkarte aus, die dann in der anderen Registerkarte in Echtzeit erscheinen.
Das Endergebnis sollte wie folgt aussehen:
Überlegungen zur Produktion
Während sich unser Beispiel hervorragend für die Entwicklung eignet, müssen bei produktiven WebSocket-Anwendungen zusätzliche Aspekte wie Verbindungsverwaltung, Authentifizierung und der Umgang mit Netzwerkunterbrechungen berücksichtigt werden. Moderne Plattformen wie Upsun erledigen viele dieser Aufgaben automatisch, einschließlich der Lastverteilung von WebSocket-Verbindungen und der Verwaltung der SSL-Terminierung.
Die Entwicklung einer WebSocket-Anwendung ist nur der Anfang; wenn sie zuverlässig in der Produktion läuft, werden die Dinge interessant. Sie müssen die Skalierung handhaben, wenn Ihre Chat-Anwendung viral wird, Leistungsprobleme bei Echtzeitverbindungen beheben und neue Funktionen testen, ohne die Live-Erfahrung für Ihre Benutzer zu beeinträchtigen.
Dies ist der Punkt, an dem Upsun glänzt. Als eine auf Entwickler fokussierte Plattform, die für moderne Anwendungen gebaut wurde, macht Upsun die Bereitstellung von WebSocket-Anwendungen erfrischend einfach. Jeder Git-Push erstellt automatisch eine komplette Vorschauumgebung, einschließlich Ihres WebSocket-Servers, der Datenbank und aller Abhängigkeiten, so dass Sie Echtzeit-Funktionen mit tatsächlichen Daten testen können, bevor sie in Produktion gehen.
Und dank der integrierten Beobachtbarkeit und Leistungsüberwachung können Sie Verbindungsengpässe oder Probleme bei der Nachrichtenübermittlung erkennen, bevor Ihre Benutzer sie bemerken. Ganz gleich, ob Sie eine einfache Chat-App oder ein komplexes Echtzeit-Kollaborationstool entwickeln, Upsun kümmert sich um die Komplexität der Infrastruktur, damit Sie sich auf das konzentrieren können, was Ihre Anwendung ausmacht.
Sind Sie bereit zu sehen, wie einfach die Bereitstellung von WebSockets sein kann? Starten Sie Ihre kostenlose Testversion und bringen Sie Ihre Echtzeit-App in wenigen Minuten zum Laufen.