I’ve managed to write a csharp websocket server and clients can connect, however the clients send a ping
message but the server doesnt respond with a pong
so the client drops the connection.
On further investigation, it turns out I need to have a ReadAsync
running to capture the ping message, but then it’s in an await state so blocks everything!
I would love to get to the underlying socket so I could do a socket.available
to check for read data but thats not possible.
So how are you supposed to write a websocket server in c# (and dont say SignalR!) that responds to a ping and can determine if the client has dropped!
using System.Net.Sockets;
using System.Net.WebSockets;
using System.Text;
class Program
{
static async Task ClientHandler(HttpContext context)
{
using WebSocket socket = await context.WebSockets.AcceptWebSocketAsync();
Console.WriteLine("Websocket client connected from {0}", socket.SubProtocol);
var buffer = new byte[1024 * 4];
WebSocketReceiveResult payload = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
string? message = Encoding.UTF8.GetString(buffer);
Console.WriteLine("Received {0}", message);
// workaround for replying to ping from client which requires ReceiveAsync to be active
// Task.Run(async () =>
// {
// await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
// });
while (socket.State == WebSocketState.Open)
{
Console.WriteLine("Sending message...");
byte[] msg = System.Text.Encoding.Default.GetBytes("Hello, World!");
await socket.SendAsync(new ArraySegment<byte>(msg, 0, msg.Length), payload.MessageType, true, CancellationToken.None);
Thread.Sleep(200);
}
await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "No more messages", CancellationToken.None);
Console.WriteLine("Connection closed");
}
static void Main()
{
var app = WebApplication.CreateBuilder().Build();
app.UseWebSockets();
app.Use(async (context, next) =>
{
if (context.Request.Path == "/")
if (context.WebSockets.IsWebSocketRequest)
await ClientHandler(context);
else
context.Response.StatusCode = StatusCodes.Status400BadRequest;
else
await next(context);
});
app.Run("http://127.0.0.1:8001");
}
}