This question already has an answer here:
I am trying to learn async/await
so this may sound like a dumb question, but I am currently working on a basic TCP server and trying to use async/await
instead of manual threading to handle multiple connections.
In a NetworkClient
class I have the following method:
public async Task Start()
{
using (var reader = new StreamReader(_socket.GetStream()))
{
while (_server.IsRunning)
{
try
{
var content = await reader.ReadLineAsync().ConfigureAwait(false);
if (content == null)
{
Console.WriteLine("Client {0} disconnected", _id);
return;
}
Console.WriteLine("Client {0} wrote: {1}", _id, content);
}
catch (IOException)
{
Console.WriteLine("Client {0} disconnected", _id);
return;
}
}
}
}
My loop that listens for client connections contains the following code:
private void ListenForClients()
{
var numClients = 0;
while (IsRunning)
{
var tcpClient = _listener.AcceptTcpClient();
var netClient = new NetworkClient(this, tcpClient, numClients);
netClient.Start();
Console.WriteLine("Client {0} Connected", numClients);
numClients++;
}
}
This works as I expect it, allowing multiple telnet connections to connect and send messages to the server at the same time. However, resharper tells me that I should be adding await
to netClient.Start();
because otherwise it won't block. However, I do not want it to block!
The fact that Resharper is giving me a warning like this makes me wonder if I am approaching the async/await
system incorrectly. Why does Resharper want me to add await
to this line of code, and what is the correct way to work with this so that netClient.Start();
does not block other tcp connections from joining?
However, resharper tells me that I should be adding await to netClient.Start(); because otherwise it won't block. However, I do not want it to block!
ReSharper will warn about this situation because it's usually an error.
In your case, you can create a private Task
member in your type that represents the Start
method and assign it rather than await
it:
startTask = netClient.Start();
This should avoid the warning, and give you the ability to determine when the Start
method exits and detect any exceptions it throws.
You Start
method is not really asynchronous - it looks like it waits for connection to happen synchronously and than asynchronously reads data. As result your code in ListenForClients
actually does work the way you expect - synchronous part of Start
finishes before Console.WriteLine
(so it prints correct text) and than asynchronous part will run by itself without anyone waiting for result.
This code is essentially the same as "connect + fire and forget new thread to handle reading the data".
async
/await
shine when you need to write sequential code with asynchronous operations. In you case you really need parallel operations - some other construct would be probably better to starting multiple listeners. Code for each listener will likely benefit of using await
- much simpler to use await read/await write in a loop instead of multiple states with events (or even worse EndSend/SendReceive...).
Start
method is meant to look for clients synchronously, but once a client is connected it needs to asynchronously wait for data for that client. That's what I have and that works. The problem is resharper wants me to await netClient.Start();
which would then cause it to synchronously block when waiting for new input from clients and never accept any new tcp clients - KallDrexxawiat
-ing async
function you are writing code that looks broken - you'd have to put half page comment in code explaining why it is OK. Try to split Start into 2 functions and explicitly kick of reading on new thread. Note: I think you use "synchronously" in 2 meanings - one "blocking wait on current thread" (how first part of Start behaves) and another "code in my function will not move past that point till operation is done potentially not blocking the thread" (how await
behaves). - Alexei Levenkov
async
does nothing without (as well as before and, sometimes, even after)await
. It is just telling to compiler thatawait
might be used in a method - Gennady Vanin Геннадий ВанинStart()
method clearly has anawait
call in it. The problem is the non-async method is calling an async method, band Resharper is convinced I should be using await for it even though that's not the behavior I want - KallDrexxasync
method havingawait
in its body - Gennady Vanin Геннадий Ванин