async await usage with TcpClient
Solution 1
I ended up using length-prefixed messages, prefixing every packet by 4 bytes representing the length of the data to come.
Solution 2
The TcpClient.Connected
value is not updated immediately. According to MSDN:
true
if the Client socket was connected to a remote resource as of the most recent operation; otherwise,false
.
So having TcpClient.Connected
as a while loop condition is not a good choice.
TcpClient.DataAvailable
is used for synchronous operations and do not used for asynchronous.
Update your code to:
static async void ReadAsync(TcpClient client)
{
NetworkStream ns = client.GetStream();
MemoryStream ms = new MemoryStream();
byte[] buffer = new byte[1024];
while(true) {
int bytesRead = await ns.ReadAsync(buffer, 0, buffer.Length);
if (bytesRead <= 0)
break;
ms.Write(buffer, 0, bytesRead);
HandleMessage(ms.ToArray());
ms.Seek(0, SeekOrigin.Begin);
}
}
When ReadAsync
return 0, it means TCP connection closing or closed. In MSDN:
The value of the
TResult
parameter contains the total number of bytes read into the buffer. The result value can be less than the number of bytes requested if the number of bytes currently available is less than the requested number, or it can be 0 (zero) if the end of the stream has been reached.
Philippe Paré
Software developer at Devolutions. Also working on a voxel based RPG. I Like regexes now, for some reason.
Updated on June 13, 2022Comments
-
Philippe Paré almost 2 years
I recently started using the new C#5.0 "async" and "await" keywords. I thought I got the twist but realized one thing that made me doubt. Here's how I was asynchronously receiving data from a remote TcpClient. Once I accept the connection I call this function :
static async void ReadAsync(TcpClient client) { NetworkStream ns = client.GetStream(); MemoryStream ms = new MemoryStream(); byte[] buffer = new byte[1024]; while(client.Connected) { int bytesRead = await ns.ReadAsync(buffer, 0, buffer.Length); ms.Write(buffer, 0, bytesRead); if (!ns.DataAvailable) { HandleMessage(ms.ToArray()); ms.Seek(0, SeekOrigin.Begin); } } }
After data is received, the loop just goes on and on without reading anything. I tested this with a Console.WriteLine in the loop. Am I using it correctly? I feel I should not be using a while loop...