Skip to content

Instantly share code, notes, and snippets.

@mrpmorris
Last active January 22, 2022 16:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mrpmorris/147d72c62038e0bfb0ec26e75b353664 to your computer and use it in GitHub Desktop.
Save mrpmorris/147d72c62038e0bfb0ec26e75b353664 to your computer and use it in GitHub Desktop.
An HTTP server accepting WebSockets
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace ConsoleApp15;
public static class Program
{
public static async Task Main(string[] args)
{
IHostBuilder hostBuilder = Host.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
services.AddSingleton<Server>();
services.AddHostedService<Server>();
});
IHost host = hostBuilder.Build();
await host.RunAsync();
}
}
using ConsoleApp15.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System.Net;
using System.Net.WebSockets;
using System.Text;
namespace ConsoleApp15;
public class Server : IHostedService
{
private readonly ILogger<Server> Logger;
private readonly HttpListener HttpListener = new();
public Server(ILogger<Server> logger)
{
Logger = logger ?? throw new ArgumentNullException(nameof(logger));
HttpListener.Prefixes.Add("http://localhost:8080/");
}
public async Task StartAsync(CancellationToken cancellationToken)
{
Logger.LogInformation("Started");
HttpListener.Start();
while (!cancellationToken.IsCancellationRequested)
{
HttpListenerContext? context = await HttpListener.GetContextAsync().WithCancellationToken(cancellationToken);
if (context is null)
return;
if (!context.Request.IsWebSocketRequest)
context.Response.Abort();
else
{
HttpListenerWebSocketContext? webSocketContext =
await context.AcceptWebSocketAsync(subProtocol: null).WithCancellationToken(cancellationToken);
if (webSocketContext is null)
return;
string clientId = Guid.NewGuid().ToString();
WebSocket webSocket = webSocketContext.WebSocket;
_ = Task.Run(async() =>
{
while (webSocket.State == WebSocketState.Open && !cancellationToken.IsCancellationRequested)
{
await Task.Delay(1000);
await webSocket.SendAsync(
Encoding.ASCII.GetBytes($"Hello {clientId}\r\n"),
WebSocketMessageType.Text,
endOfMessage: true,
cancellationToken);
}
});
_ = Task.Run(async() =>
{
byte[] buffer = new byte[1024];
var stringBuilder = new StringBuilder(2048);
while (webSocket.State == WebSocketState.Open && !cancellationToken.IsCancellationRequested)
{
WebSocketReceiveResult receiveResult =
await webSocket.ReceiveAsync(buffer, cancellationToken);
if (receiveResult.Count == 0)
return;
stringBuilder.Append(Encoding.ASCII.GetString(buffer, 0, receiveResult.Count));
if (receiveResult.EndOfMessage)
{
Console.WriteLine($"{clientId}: {stringBuilder}");
stringBuilder = new StringBuilder();
}
}
});
}
}
}
public Task StopAsync(CancellationToken cancellationToken)
{
Logger.LogInformation("Stopping...");
HttpListener.Stop();
Logger.LogInformation("Stopped");
return Task.CompletedTask;
}
}
namespace ConsoleApp15.Extensions;
public static class TaskExtensions
{
public static async Task<T?> WithCancellationToken<T>(this Task<T> source, CancellationToken cancellationToken)
{
var cancellationTask = new TaskCompletionSource<bool>();
cancellationToken.Register(() => cancellationTask.SetCanceled());
_ = await Task.WhenAny(source, cancellationTask.Task);
if (cancellationToken.IsCancellationRequested)
return default;
return source.Result;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment