I'm trying to implement a TcpListener using the TPL. I'm not sure If I'm doing everything correctly though. I'm trying to keep the code as small as possible as well. It all works fine in a console application.
public async Task RunAsync(CancellationToken cancellationToken)
{
var listener = new TcpListener(ip, port);
listener.Start();
while (!cancellationToken.IsCancellationRequested)
{
await AcceptClientAsync(listener, encoding, progress, cancellationToken);
}
listener.Stop();
}
Here is the AcceptClientAsync
method: (Sorry for the weird formatting. StyleCop likes to do that.)
private async Task AcceptClientAsync(TcpListener tcpListener, Encoding encoding, IProgress<string> progress, CancellationToken cancellationToken)
{
var client = await tcpListener.AcceptTcpClientAsync();
this.Connection = new ConnectionState { TcpClient = client };
while (client.Connected && !cancellationToken.IsCancellationRequested)
{
await
this.ReadStringAsync(this.Connection, encoding, progress)
.ContinueWith(
task =>
progress.Report(
string.Format("Client {0} disconnected.", Connection.TcpClient.Client.RemoteEndPoint)),
TaskContinuationOptions.OnlyOnFaulted);
}
}
And the ReadStringAsync
method:
private async Task ReadStringAsync(ConnectionState connection, Encoding encoding, IProgress<string> progress)
{
var stream = connection.TcpClient.GetStream();
if (connection.Read > 0)
{
var encoded = encoding.GetString(connection.Buffer, 0, connection.Read);
connection.StringBuilder.Append(encoded);
}
var decoded = connection.StringBuilder.ToString();
if (decoded.Contains("<End>"))
{
progress.Report(decoded.Replace("<End>", string.Empty));
}
connection.Read = await stream.ReadAsync(connection.Buffer, 0, connection.Buffer.Length);
}
I'd also like to keep using the IProgress<>
interface and support cancellation via CancellationToken
s.