Web Sockets
Esta página foi traduzida automaticamente do inglês. Ler o original
O Sisk também oferece suporte a web sockets, permitindo receber e enviar mensagens ao cliente.
Esse recurso funciona bem na maioria dos navegadores, mas no Sisk ainda é experimental. Por favor, se encontrar algum bug, reporte‑o no GitHub.
Aceitando mensagens #
As mensagens WebSocket são recebidas em ordem, enfileiradas até serem processadas por ReceiveMessageAsync. Esse método não retorna mensagem quando o tempo limite é atingido, quando a operação é cancelada ou quando o cliente está desconectado.
O tamanho máximo de uma mensagem recebida é HttpServerConfiguration.MaximumContentLength, que tem o padrão de 100 MB desde o Sisk 1.7. Quando um cliente envia uma mensagem maior, a conexão é fechada com o status MessageTooBig e ReceiveMessageAsync não retorna mensagem.
Só pode ocorrer uma operação de leitura ou escrita simultaneamente; portanto, enquanto você aguarda uma mensagem com ReceiveMessageAsync, não é possível escrever para o cliente conectado.
router.MapGet("/connect", async (HttpRequest req) =>
{
using var ws = await req.GetWebSocketAsync();
while (await ws.ReceiveMessageAsync(timeout: TimeSpan.FromSeconds(30)) is { } receivedMessage)
{
string msgText = receivedMessage.GetString();
Console.WriteLine("Received message: " + msgText);
await ws.SendAsync("Hello!");
}
return await ws.CloseAsync();
});Conexão persistente #
O exemplo abaixo mostra como usar uma conexão websocket persistente, onde você recebe as mensagens, as processa e finaliza o uso do socket.
router.MapGet("/connect", async (HttpRequest req) =>
{
using var ws = await req.GetWebSocketAsync();
WebSocketMessage? msg;
askName:
await ws.SendAsync("What is your name?");
msg = await ws.ReceiveMessageAsync();
if (msg is null)
return await ws.CloseAsync();
string name = msg.GetString();
if (string.IsNullOrEmpty(name))
{
await ws.SendAsync("Please, insert your name!");
goto askName;
}
askAge:
await ws.SendAsync("And your age?");
msg = await ws.ReceiveMessageAsync();
if (msg is null)
return await ws.CloseAsync();
if (!Int32.TryParse(msg?.GetString(), out int age))
{
await ws.SendAsync("Please, insert an valid number");
goto askAge;
}
await ws.SendAsync($"You're {name}, and you are {age} old.");
return await ws.CloseAsync();
});Política de Ping #
Semelhante à política de ping em Server‑Side Events, você também pode configurar uma política de ping para manter a conexão TCP aberta caso haja inatividade.
ws.PingPolicy.Start(
dataMessage: "ping-message",
interval: TimeSpan.FromSeconds(10));Conexões gerenciadas #
Ao aceitar um WebSocket, você pode fornecer um identificador. Sockets identificados são registrados em HttpServer.WebSockets, permitindo que o servidor encontre conexões ativas fora da rota que as aceitou.
router.MapGet("/connect/<userId>", async (HttpRequest req) =>
{
string userId = req.RouteParameters["userId"].GetString();
using var ws = await req.GetWebSocketAsync(identifier: $"user:{userId}");
ws.State = userId;
ws.PingPolicy.Start(
dataMessage: "ping",
interval: TimeSpan.FromSeconds(10));
while (await ws.ReceiveMessageAsync(TimeSpan.FromMinutes(5)) is { } message)
{
await ws.SendAsync("Received: " + message.GetString());
}
return await ws.CloseAsync();
});De outra parte da aplicação, consulte a coleção por identificador ou predicado:
HttpWebSocket? socket = server.WebSockets.GetByIdentifier("user:42");
if (socket is { IsClosed: false })
{
await socket.SendAsync("Your report is ready.");
}
foreach (HttpWebSocket activeSocket in server.WebSockets.Find(id => id.StartsWith("user:")))
{
await activeSocket.SendAsync("Broadcast message");
}Cada HttpWebSocket expõe Identifier, State, IsClosed e PingPolicy. A coleção também expõe All(), Find(...), GetByIdentifier(...), ActiveConnections e DropAll() para estratégias de conexão gerenciadas pelo servidor.