csharp-websockets

Cómo usar websockets en C# sin librerías

Vamos a ver como usar WebSockets en C# sin emplear bibliotecas, únicamente con el código y funcionalidades estándar disponibles en .NET.

Los WebSockets son una tecnología que permite la comunicación bidireccional en tiempo real entre un servidor y un cliente a través de un único canal TCP/IP.

A diferencia de las peticiones HTTP, los WebSockets mantienen una conexión persistente entre el cliente y el servidor. Esto permite una comunicación más rápida y bidireccional.

C# proporciona soporte nativo para los WebSockets a través del espacio de nombres System.Net.WebSockets. Aunque es posible utilizar los WebSockets nativos de C#, su uso “a pelo” es una auténtico peñazo.

Pero, por si alguien lo necesita aquí tenéis un ejemplo de código. Como ejercicio de explicación del funcionamiento, no está mal. Aunque solo sea para apreciar luego las librerías que veremos en próximas entradas (tenéis los enlaces abajo).

Ejemplos de Websocket nativos en .NET

Vamos a ver el código necesario para crear una comunicación WebSocket en C# entre un servidor y cliente.

Ejemplo de servidor

Así sería el código del servidor.

using System.Net.WebSockets;
using System.Net;
using System.Text;

var httpListener = new HttpListener();
httpListener.Prefixes.Add("http://localhost:9006/");
httpListener.Start();

Console.WriteLine("Listening for WebSocket connections...");

while (true)
{
    var context = await httpListener.GetContextAsync();
    if (context.Request.IsWebSocketRequest)
    {
        var webSocketContext = await context.AcceptWebSocketAsync(subProtocol: null);
        var webSocket = webSocketContext.WebSocket;

        Console.WriteLine("Client connected");

        var receiveBuffer = new byte[1024];
        if (webSocket.State == WebSocketState.Open)
        {
            var receiveResult = await webSocket.ReceiveAsync(new ArraySegment<byte>(receiveBuffer), CancellationToken.None);
            if (receiveResult.MessageType == WebSocketMessageType.Text)
            {
                var receivedMessage = Encoding.UTF8.GetString(receiveBuffer, 0, receiveResult.Count);
                Console.WriteLine($"Received message: {receivedMessage}");

                var buffer = Encoding.UTF8.GetBytes($"Hello from server");
                await webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
            }
            else if (receiveResult.MessageType == WebSocketMessageType.Close)
            {
                await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
                Console.WriteLine("WebSocket closed.");
            }
        }
    }
    else
    {
        context.Response.StatusCode = 400;
        context.Response.Close();
    }
}

Ejemplo de cliente

Y así el código del cliente.

using System.Net.WebSockets;
using System.Text;

using var ws = new ClientWebSocket();

var uri = new Uri("ws://localhost:9006");
await ws.ConnectAsync(uri, CancellationToken.None);

Console.WriteLine("Connected");

var message = "Hello from client!";
var buffer = Encoding.UTF8.GetBytes(message);
await ws.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);

var receiveBuffer = new byte[1024];
var receiveResult = await ws.ReceiveAsync(new ArraySegment<byte>(receiveBuffer), CancellationToken.None);
var receivedMessage = Encoding.UTF8.GetString(receiveBuffer, 0, receiveResult.Count);

Console.WriteLine($"Received message: {receivedMessage}");

Como vemos, es un auténtico peñazo hacerte un Websocket a mano. Lo normal es que vayamos a usar alguna biblioteca. Aquí tenéis un tutoriales sobre la librería WebSocketSharp y aqui tutoriales sobre la librería WatsonWebsocket para simplificar el uso de los WebSockets en C#.