Web ソケット
このページは英語から自動翻訳されています。 原文を読む
Sisk は Web ソケットもサポートしており、クライアントとのメッセージの受信および送信が可能です。
この機能はほとんどのブラウザーで問題なく動作しますが、Sisk ではまだ実験的な段階です。バグを見つけた場合は、GitHub で報告してください。
メッセージの受信 #
WebSocket メッセージは順番に受信され、ReceiveMessageAsync によって処理されるまでキューに保持されます。このメソッドは、タイムアウトに達した場合、操作がキャンセルされた場合、またはクライアントが切断された場合にメッセージを返しません。
受信メッセージの最大サイズは HttpServerConfiguration.MaximumContentLength で、Sisk 1.7 以降はデフォルトで 100 MB です。クライアントがそれより大きなメッセージを送信した場合、接続は MessageTooBig ステータスで閉じられ、ReceiveMessageAsync はメッセージを返しません。
読み取りと書き込みの操作は同時に一つしか実行できないため、ReceiveMessageAsync でメッセージを待機している間は、接続されたクライアントへ書き込むことはできません。
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();
});永続的な接続 #
以下の例は、メッセージを受信し処理し、ソケットの使用を終了するまで、永続的な WebSocket 接続を利用する方法を示しています。
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();
});Ping ポリシー #
Server Side Events の Ping ポリシーと同様に、非アクティブ時でも TCP 接続を維持するために Ping ポリシーを設定することができます。
ws.PingPolicy.Start(
dataMessage: "ping-message",
interval: TimeSpan.FromSeconds(10));管理された接続 #
WebSocket を受け入れる際に識別子を指定できます。識別されたソケットは HttpServer.WebSockets に登録され、サーバーはそれらを受け入れたルート以外からでもアクティブな接続を検索できるようになります。
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();
});アプリケーションの別の部分から、識別子または述語でコレクションを照会できます。
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");
}HttpWebSocket は Identifier、State、IsClosed、PingPolicy を公開します。コレクションはさらに、サーバー管理の接続戦略のために All()、Find(...)、GetByIdentifier(...)、ActiveConnections、DropAll() を提供します。