Introdução ao WebSocket em C# para aplicações em tempo real
As aplicações web modernas exigem cada vez mais a transmissão instantânea de dados entre cliente e servidor. O protocolo HTTP tradicional, que opera no esquema "requisição-resposta", é ineficiente para tarefas onde são importantes baixa latência e atualização constante de informações: chats online, cotações de bolsa, jogos multijogador, sistemas de monitoramento. O WebSocket vem em socorro — um protocolo que fornece uma conexão bidirecional permanente.
No ecossistema C# (.NET), a implementação do WebSocket está disponível tanto através das classes internas do namespace System.Net.WebSockets, quanto através da biblioteca de alto nível SignalR. Neste artigo, abordaremos ambas as abordagens, escreveremos exemplos funcionais e discutiremos as características arquitetônicas de aplicações em tempo real. O material será útil tanto para desenvolvedores .NET iniciantes quanto para os experientes.
Fundamentos do WebSocket: como funciona em C#
WebSocket é um protocolo que, após um handshake HTTP inicial (upgrade request), transforma a conexão em um modo bidirecional permanente. Em C#, o trabalho com WebSocket é baseado em programação assíncrona usando as palavras-chave async e await.
Criando um servidor WebSocket simples em C#
Vamos considerar um exemplo básico de servidor que aceita conexões WebSocket e responde com eco ao cliente. Para isso, usamos a classe interna HttpListener ou Kestrel (ASP.NET Core). Abaixo está um exemplo baseado em ASP.NET Core.
// Startup.cs ou Program.cs (API mínima)
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseWebSockets();
app.Map("/ws", async (HttpContext context) =>
{
if (context.WebSockets.IsWebSocketRequest)
{
using var webSocket = await context.WebSockets.AcceptWebSocketAsync();
await Echo(webSocket);
}
else
{
context.Response.StatusCode = 400;
}
});
async Task Echo(WebSocket webSocket)
{
var buffer = new byte[1024 * 4];
while (webSocket.State == WebSocketState.Open)
{
var result = await webSocket.ReceiveAsync(
new ArraySegment<byte>(buffer), CancellationToken.None);
if (result.MessageType == WebSocketMessageType.Close)
{
await webSocket.CloseAsync(
WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
}
else
{
// Envia os dados de volta (eco)
await webSocket.SendAsync(
new ArraySegment<byte>(buffer, 0, result.Count),
result.MessageType,
result.EndOfMessage,
CancellationToken.None);
}
}
}
app.Run();
O código demonstra a mecânica básica: AcceptWebSocketAsync transforma a requisição HTTP em WebSocket, e os métodos ReceiveAsync e SendAsync garantem a troca assíncrona de dados. É importante tratar o estado da conexão e fechá-la corretamente.
Cliente WebSocket em C#
A parte do cliente também é simples. Usamos a classe ClientWebSocket:
using System.Net.WebSockets;
async Task ConnectAndSend()
{
using var client = new ClientWebSocket();
await client.ConnectAsync(new Uri("ws://localhost:5000/ws"), CancellationToken.None);
var message = "Olá, WebSocket!";
var bytes = Encoding.UTF8.GetBytes(message);
await client.SendAsync(new ArraySegment<byte>(bytes),
WebSocketMessageType.Text, true, CancellationToken.None);
var buffer = new byte[1024];
var result = await client.ReceiveAsync(
new ArraySegment<byte>(buffer), CancellationToken.None);
var response = Encoding.UTF8.GetString(buffer, 0, result.Count);
Console.WriteLine($"Resposta: {response}");
}
```