patterncsharpMinor
Console chat server
Viewed 0 times
serverconsolechat
Problem
I'm just looking for feedback on correctness of my understanding of async/await. I'm curious about the
After running, one can connect by telnetting to localhost 7776.
```
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
namespace ChatTutorial.ConsoleServer
{
class Program
{
static void Main(string[] args)
{
try
{
var server = new ChatServer();
server.Start();
Console.WriteLine("Listening....");
Console.ReadLine();
}
catch (Exception ex)
{
Logger.PrintException(ex, "Main");
}
}
}
internal class ChatServer
{
private readonly TcpListener _listener = new TcpListener(IPAddress.Parse("0.0.0.0"), 7776);
private readonly Dictionary _clients = new Dictionary();
public async void Start()
{
try
{
_listener.Start();
while (true)
{
try
{
Console.WriteLine("Listening...");
var client = await _listener.AcceptTcpClientAsync();
Console.WriteLine("Client connected");
var id = Guid.NewGuid().ToString();
_clients.Add(id, new LocalClient(client, ReceivedMessage, ClientClosed, id));
}
catch (Exception ex)
{
Console.WriteLine("Start() While() '{0}', '{1}'", ex.Message, ex.StackTrace);
}
}
}
catch (Exception ex)
{
Task.Run inside of the StartReceive() method. Resharper (or maybe just the compiler) warns against doing this without an await, but I think in this case, it's ok.After running, one can connect by telnetting to localhost 7776.
```
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
namespace ChatTutorial.ConsoleServer
{
class Program
{
static void Main(string[] args)
{
try
{
var server = new ChatServer();
server.Start();
Console.WriteLine("Listening....");
Console.ReadLine();
}
catch (Exception ex)
{
Logger.PrintException(ex, "Main");
}
}
}
internal class ChatServer
{
private readonly TcpListener _listener = new TcpListener(IPAddress.Parse("0.0.0.0"), 7776);
private readonly Dictionary _clients = new Dictionary();
public async void Start()
{
try
{
_listener.Start();
while (true)
{
try
{
Console.WriteLine("Listening...");
var client = await _listener.AcceptTcpClientAsync();
Console.WriteLine("Client connected");
var id = Guid.NewGuid().ToString();
_clients.Add(id, new LocalClient(client, ReceivedMessage, ClientClosed, id));
}
catch (Exception ex)
{
Console.WriteLine("Start() While() '{0}', '{1}'", ex.Message, ex.StackTrace);
}
}
}
catch (Exception ex)
{
Solution
As the latecomer to the party, I'll take it from V3...
First,
For a simple example, you don't need to do any cleanup at all. Once your app exits, the OS will clean up after it. Doing cleanup just before application exit is just a waste of effort.
If you do want to cleanly stop an asynchronous system, you should be using
On a side note, it is almost impossible to shut down a socket without seeing exceptions; the general rule of thumb is that once you decide to shut down, just ignore all errors until it's done.
You can find out more about socket programming in my TCP/IP .NET Sockets FAQ. However, I highly recommend that you find another sample project to explore
First,
async void should only be used for event handlers. I'd much rather see Start return a Task representing the listening loop.For a simple example, you don't need to do any cleanup at all. Once your app exits, the OS will clean up after it. Doing cleanup just before application exit is just a waste of effort.
If you do want to cleanly stop an asynchronous system, you should be using
CancellationToken - create a CTS in Main and then pass the token to Start. From there things get tricky, as many operations (such as AcceptTcpClientAsync) do not take a CancellationToken. There's an old trick in Windows programming where you can close the underlying handle (in this case, Stop the TcpListener) which will cause any outstanding asynchronous operations on that handle to complete with an error.On a side note, it is almost impossible to shut down a socket without seeing exceptions; the general rule of thumb is that once you decide to shut down, just ignore all errors until it's done.
You can find out more about socket programming in my TCP/IP .NET Sockets FAQ. However, I highly recommend that you find another sample project to explore
async and await (if you like to learn by example, there's a good tutorial built in to LINQPad). There is no such thing as a "simple" TCP/IP chat server. I've had many people ask me for sample async socket code, but I haven't given any out for a very simple reason: it's not as hard as it used to be, but it's still really hard to get right!Context
StackExchange Code Review Q#29000, answer score: 6
Revisions (0)
No revisions yet.