Issue
Description
I would like to read asynchronously from a NetworkStream
or SSLStream
using their abstract Stream
parent class. There are different ways to read asynchronously from stream:
- Asynchronous Programming Model (APM): It uses
BeginRead
andEndRead
operations. - Task Parallel Library (TPL): It uses
Task
and creates task continuations. - Task-based Asynchronous Pattern (TAP): Operations are suffixed Async and
async
andawait
keyword can be used.
I am mostly interested using the TAP pattern to achieve asynchronous read operation. Code below, asynchronously read to the end of stream and returns with the data as byte array:
internal async Task<byte[]> ReadToEndAsync(Stream stream)
{
byte[] buffer = new byte[4096];
using (MemoryStream memoryStream = new MemoryStream())
{
int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
while (bytesRead != 0)
{
// Received datas were aggregated to a memory stream.
await memoryStream.WriteAsync(buffer, 0, bytesRead);
bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
}
return memoryStream.ToArray();
}
}
The buffer size is 4096kB. If the transferred data is more than the buffer size then it continues to read until 0 (zero), the end of the stream. It works with FileStream
but it hangs indefinitely at the ReadAsync
operation using NetworkStream
or SslStream
. These two stream behave differently than other streams.
The problem lies behind that the network stream ReadAsync
will only return with 0 (zero) when the Socket
communication is closed. However I do not want to close the communication every time a data is transferred through the network.
Question
How can I avoid the blocking call of the ReadAsync
without closing the Socket
communication?
Solution
I would like to read asynchronously from a NetworkStream or SSLStream using their abstract Stream parent class.
Do you really need to? TCP/IP socket communication is quite complex to do correctly. I strongly recommend self-hosting an HTTP API or something like that instead.
The problem lies behind that the network stream ReadAsync will only return with 0 (zero) when the Socket communication is closed.
Yes, and the code you posted only returns a result when the entire stream has been read.
So, what you need is a different return condition. Specifically, you need to know when a single message has been read from the stream. What you need is message framing, as described on my blog.
I also have some sample code on my blog showing one of the simplest message framing solutions (length prefix). Take careful note of the complexity and length of the simplest solution, and consider whether you really want to write socket-level code.
If you do want to continue writing socket applications, I recommend watching my YouTube series on asynchronous TCP/IP socket programming.
Answered By - Stephen Cleary Answer Checked By - Senaida (PHPFixing Volunteer)
0 Comments:
Post a Comment
Note: Only a member of this blog may post a comment.