WebSocket en C#: aplicaciones en tiempo real de nivel avanzado

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción: Por qué WebSocket en C# es la elección de los profesionales

En el desarrollo web moderno, la interacción en tiempo real se ha convertido en un estándar. Plataformas de trading, sistemas de monitoreo, juegos en línea y chats: todos requieren transmisión instantánea de datos. La tecnología WebSocket en C# (.NET) proporciona una herramienta potente y flexible para crear este tipo de aplicaciones. A diferencia de las consultas HTTP, WebSocket establece una conexión bidireccional permanente, lo que reduce drásticamente la latencia y la carga del servidor.

En este artículo, exploraremos aspectos avanzados del trabajo con WebSocket en C#. Aprenderá cómo construir un servidor tolerante a fallos, gestionar miles de conexiones simultáneas, manejar errores e integrar WebSocket con frameworks populares. El material está dirigido a desarrolladores que ya conocen los fundamentos de .NET y la programación asíncrona.



Arquitectura de un servidor WebSocket avanzado en C#

Un ejemplo básico de servidor WebSocket en C# a menudo se limita a un solo manejador. Para soluciones de producción se requiere una arquitectura bien pensada. Veamos los componentes clave.



Gestión de conexiones e identificación de clientes

En lugar de una simple lista de conexiones, use ConcurrentDictionary para un almacenamiento seguro en subprocesos. A cada cliente se le asigna un identificador único (GUID) y se almacenan metadatos (por ejemplo, nombre de usuario, grupo).

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);}

Este enfoque permite enviar mensajes fácilmente a usuarios específicos, grupos o a todos a la vez.



Manejo de mensajes fragmentados

En aplicaciones reales, los datos pueden llegar en fragmentos. El método estándar ReceiveAsync devuelve un solo fragmento. Para ensamblar el mensaje completo, use un bucle:

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

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

return ms.ToArray();}

Esto es crítico para la transmisión de objetos JSON grandes o datos binarios (imágenes, archivos).



Escalabilidad: SignalR vs Raw WebSocket

Para aplicaciones complejas surge la pregunta de elegir entre WebSocket de bajo nivel y SignalR, una biblioteca de Microsoft que abstrae WebSocket. Veamos los escenarios.



Cuándo usar Raw WebSocket

  • Máximo rendimiento y mínimo overhead.
  • Protocolo de transmisión propio (datos binarios, tramas personalizadas).
  • Integración con clientes que no son .NET (por ejemplo, Go o Rust).
  • Control total sobre la gestión de conexiones.


Cuándo elegir SignalR

  • Escalabilidad automática mediante Redis Backplane o Azure SignalR Service.
  • Soporte para transportes alternativos (Long Polling, Server-Sent

Blogs

Book Recommendations