I'm trying to get a "simple" Tcp Server working using Async/Await. The goal is to use TcpListener that will listen for client connections and then process asynchronously and non-blocking both read and writes for all connected clients.
What I have so far accepts connections, however what I'm seeing is the first connected client I can see the message it sends, and the messages that are received. The second and subsequent clients seemed to be blocked by the first client. I have the following code.
Do I need to use Task.Run() on the ListenerLoop() and maybe on the ReadLoop()?
Start
public async Task Start()
{
_cancellationToken = new CancellationTokenSource();
_listener.Start();
await ListenerLoop();
}
ListenerLoop
public async Task ListenerLoop()
{
var lingerOption = new LingerOption(true, 0);
while (!_cancellationToken.IsCancellationRequested)
{
var client = await _listener.AcceptTcpClientAsync();
client.LingerState = lingerOption;
_tcpServer.FireClientConnected(_tcpServer, client);
await ReadLoop(client);
}
}
ReadLoop
public async Task ReadLoop(TcpClient client)
{
var delimiter = _tcpServer.Delimiter;
var queuedMsg = new List<byte>();
while (!_cancellationToken.IsCancellationRequested)
{
if (!IsSocketConnected(client.Client))
{
_tcpServer.FireClientDisconnected(_tcpServer, client);
client.GetStream().Close();
client.Close();
break;
}
var bytesAvailable = client.Available;
if (bytesAvailable == 0) continue;
var bytesReceived = new List<byte>();
while (client.Available > 0 && client.Connected)
{
var nextByte = new byte[1];
await client.GetStream().ReadAsync(nextByte, 0, 1, _cancellationToken.Token);
bytesReceived.AddRange(nextByte);
if (nextByte[0] == delimiter)
{
var msg = Encoding.ASCII.GetString(queuedMsg.ToArray()) ;
_tcpServer.FireMessageReceived(_tcpServer, client, msg);
queuedMsg.Clear();
bytesReceived.Clear();
}
else
{
queuedMsg.AddRange(nextByte);
}
}
if (bytesReceived.Count > 0)
{
var msg = Encoding.ASCII.GetString(queuedMsg.ToArray());
_tcpServer.FireMessageReceived(_tcpServer, client, msg);
}
}
}