Under what conditions does a NetworkStream not rea

2020-05-06 17:19发布

In the callback for NetworkStream.BeginRead I seem to notice that all bytes are always read. I see many tutorials check to see if the BytesRead is less than the total bytes and if so, read again, but this never seems to be the case.

The condition if (bytesRead < totalBytes) never fires, even if a lot of data is sent at once (thousands of characters) and even if the buffer size is set to a very small value (16 or so).

I have not tested this with the 'old-fashioned way' as I am using Task.Factory.FromAsync instead of calling NetworkStream.BeginRead and providing a callback where I call EndRead. Perhaps Tasks automatically include this functionality of not returning until all data is read? I'm not sure.

Either way, I am still curious as to when all data would not be read at once. Is it even required to check if not all data was read, and if so, read again? I cannot seem to get the conditional to ever run.

Thanks.

1条回答
Explosion°爆炸
2楼-- · 2020-05-06 17:50

Try sending megabytes of data over a slow link. Why would the stream want to wait until it was all there before giving the caller any of it? What if the other side hadn't closed the connection - there is no concept of "all the data" at that point.

Suppose you open a connection to another server and call BeginRead (or Read) with a large buffer, but it only sends 100 bytes, then waits for your reply - what would you expect NetworkStream to do? Never give you the data, because you gave it too big a buffer? That would be highly counterproductive.

You should absolutely not assume that any stream (with the arguable exception of MemoryStream) will fill the buffer you give it. It's possible that FileStream always will for local files, but I'd expect it not to for shared files.

EDIT: Sample code which shows the buffer not being filled - making an HTTP 1.1 request (fairly badly :)

// Please note: this isn't nice code, and it's not meant to be. It's just quick
// and dirty to demonstrate the point.
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;

class Test
{
    static byte[] buffer;

    static void Main(string[] arg)
    {
        TcpClient client = new TcpClient("www.yoda.arachsys.com", 80);
        NetworkStream stream = client.GetStream();

        string text = "GET / HTTP/1.1\r\nHost: yoda.arachsys.com:80\r\n" +
            "Content-Length: 0\r\n\r\n";
        byte[] bytes = Encoding.ASCII.GetBytes(text);
        stream.Write(bytes, 0, bytes.Length);
        stream.Flush();

        buffer = new byte[1024 * 1024];
        stream.BeginRead(buffer, 0, buffer.Length, ReadCallback, stream);
        Console.ReadLine();
    }

    static void ReadCallback(IAsyncResult ar)
    {
        Stream stream = (Stream) ar.AsyncState;
        int bytesRead = stream.EndRead(ar);
        Console.WriteLine(bytesRead);
        Console.WriteLine("Asynchronous read:");
        Console.WriteLine(Encoding.ASCII.GetString(buffer, 0, bytesRead));
        string text = "Bad request\r\n";
        byte[] bytes = Encoding.ASCII.GetBytes(text);
        stream.Write(bytes, 0, bytes.Length);
        stream.Flush();
        Console.WriteLine();
        Console.WriteLine("Synchronous:");

        StreamReader reader = new StreamReader(stream);
        Console.WriteLine(reader.ReadToEnd());
    }
}
查看更多
登录 后发表回答