static async Task Main(string[] args) { var listener = new TcpListener(IPAddress.Loopback, port); var terminator = new Terminator(); var cts = new CancellationTokenSource(); var ct = cts.Token; Console.CancelKeyPress += (obj, eargs) => { Log("CancelKeyPress, stopping server"); cts.Cancel(); listener.Stop(); eargs.Cancel = true; }; listener.Start(); Log($"Listening on {port}"); using (ct.Register(() => { listener.Stop(); })) { try { while (!ct.IsCancellationRequested) { Log("Accepting new TCP client"); var client = await listener.AcceptTcpClientAsync(); var id = counter++; Log($"connection accepted with id '{id}'"); Handle(id, client, ct, terminator); } } catch (Exception e) { // await AcceptTcpClientAsync will end up with an exception Log($"Exception '{e.Message}' received"); } Log("waiting shutdown"); await terminator.Shutdown(); } }
private static async void Handle( int id, TcpClient client, CancellationToken cancellationToken, Terminator terminator) { using (terminator.Enter()) { try { using (client) { var stream = client.GetStream(); var reader = new JsonTextReader(new StreamReader(stream)) { // To support reading multiple top-level objects SupportMultipleContent = true }; var writer = new JsonTextWriter(new StreamWriter(stream)); while (true) { try { // to consume any bytes until start of object ('{') do { await reader.ReadAsync(cancellationToken); Log($"advanced to {reader.TokenType}"); } while (reader.TokenType != JsonToken.StartObject && reader.TokenType != JsonToken.None); if (reader.TokenType == JsonToken.None) { Log($"[{id}] reached end of input stream, ending."); return; } Log("Reading object"); var json = await JObject.LoadAsync(reader, cancellationToken); Log($"Object read, {cancellationToken.IsCancellationRequested}"); var request = json.ToObject <Request>(); Response response = null; switch (request.Method) { case "ECHO": response = Echo(request, json); break; case "DELAY": response = await Delay(request); break; default: response = new Response() { Status = 405 }; break; } serializer.Serialize(writer, response); await writer.FlushAsync(cancellationToken); } catch (JsonReaderException e) { Log($"[{id}] Error reading JSON: {e.Message}, ending"); var response = new Response { Status = 400, }; serializer.Serialize(writer, response); await writer.FlushAsync(cancellationToken); // close the connection because an error may not be recoverable by the reader return; } catch (Exception e) { Log($"[{id}] Exception: {e.Message}, ending"); return; } } } } finally { Log($"Ended connection {id}"); } } }
public TerminatorDisposable(Terminator terminator) { this.terminator = terminator; }