WebSocket in C#: Echtzeit-Anwendungen auf fortgeschrittenem Niveau

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: Warum WebSocket in C# die Wahl von Profis ist

In der modernen Webentwicklung ist die Echtzeit-Interaktion zum Standard geworden. Handelsplattformen, Überwachungssysteme, Online-Spiele und Chats – sie alle erfordern eine sofortige Datenübertragung. Die WebSocket-Technologie in C# (.NET) bietet ein leistungsstarkes und flexibles Werkzeug zur Erstellung solcher Anwendungen. Im Gegensatz zu HTTP-Polls stellt WebSocket eine permanente bidirektionale Verbindung her, was Latenzen und Serverlast drastisch reduziert.

In diesem Artikel betrachten wir fortgeschrittene Aspekte der Arbeit mit WebSocket in C#. Sie erfahren, wie Sie einen ausfallsicheren Server aufbauen, Tausende gleichzeitiger Verbindungen verwalten, Fehler behandeln und WebSocket in gängige Frameworks integrieren. Das Material richtet sich an Entwickler, die bereits mit den Grundlagen von .NET und asynchroner Programmierung vertraut sind.



Architektur eines fortgeschrittenen WebSocket-Servers in C#

Ein einfaches Beispiel eines WebSocket-Servers in C# beschränkt sich oft auf einen einzigen Handler. Für Produktionslösungen ist eine durchdachte Architektur erforderlich. Betrachten wir die Schlüsselkomponenten.



Verwaltung von Verbindungen und Client-Identifikation

Verwenden Sie anstelle einer einfachen Liste von Verbindungen ein ConcurrentDictionary für die threadsichere Speicherung. Jedem Client wird eine eindeutige ID (GUID) zugewiesen, und Metadaten (z. B. Benutzername, Gruppe) werden gespeichert.

public class WebSocketConnectionManager{    private readonly ConcurrentDictionary<string, WebSocket> _connections = new();    private readonly ConcurrentDictionary<string, UserMetadata> _users = new();

public string AddConnection(WebSocket socket, UserMetadata metadata) { var id = Guid.NewGuid().ToString(); _connections.TryAdd(id, socket); _users.TryAdd(id, metadata); return id; }

public async Task RemoveConnection(string id) { if (_connections.TryRemove(id, out var socket) && socket.State == WebSocketState.Open) { await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closed", CancellationToken.None); } _users.TryRemove(id, out _); }

public WebSocket? GetSocketById(string id) => _connections.GetValueOrDefault(id);}

Dieser Ansatz ermöglicht es, Nachrichten einfach an bestimmte Benutzer, Gruppen oder alle gleichzeitig zu senden.



Verarbeitung fragmentierter Nachrichten

In realen Anwendungen können Daten in Fragmenten ankommen. Die Standardmethode ReceiveAsync gibt ein einzelnes Fragment zurück. Verwenden Sie eine Schleife, um die vollständige Nachricht zusammenzusetzen:

public async Task<byte[]> ReceiveFullMessageAsync(WebSocket socket, CancellationToken ct){    using var ms = new MemoryStream();    WebSocketReceiveResult result;    var buffer = new byte[1024 * 4]; // 4KB Puffer

do { result = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), ct); ms.Write(buffer, 0, result.Count); } while (!result.EndOfMessage);

return ms.ToArray();}

Dies ist entscheidend für die Übertragung großer JSON-Objekte oder binärer Daten (Bilder, Dateien).



Skalierung: SignalR vs. Raw WebSocket

Bei komplexen Anwendungen stellt sich die Frage der Wahl zwischen Low-Level-WebSocket und SignalR – einer Bibliothek von Microsoft, die WebSocket abstrahiert. Betrachten wir die Szenarien.



Wann Raw WebSocket verwenden

  • Maximale Leistung und minimaler Overhead.
  • Eigenes Übertragungsprotokoll (binäre Daten, benutzerdefinierte Frames).
  • Integration mit Nicht-.NET-Clients (z. B. Go oder Rust).
  • Volle Kontrolle über die Verbindungsverwaltung.


Wann SignalR wählen

  • Automatische Skalierung über Redis Backplane oder Azure SignalR Service.
  • Unterstützung von Fallback-Transporten (Long Polling, Server-Sent

Blogs

Buchempfehlungen