При каких условиях NetworkStream не читает сразу все данные? - PullRequest
0 голосов
/ 11 октября 2011

В обратном вызове для NetworkStream.BeginRead Кажется, я заметил, что все байты всегда читаются. Я вижу, как во многих руководствах проверяется, меньше ли BytesRead, чем общее количество байтов, и если да, прочитайте еще раз, но, похоже, этого не происходит.

Условие if (bytesRead < totalBytes) никогда не срабатывает, даже если за один раз отправляется много данных (тысячи символов) и даже если для размера буфера задано очень маленькое значение (16 или около того).

Я не проверял это «по старинке», так как я использую Task.Factory.FromAsync вместо вызова NetworkStream.BeginRead и обеспечения обратного вызова, когда я вызываю EndRead. Возможно, Задачи автоматически включают эту функцию, не возвращая, пока все данные не будут прочитаны? Я не уверен.

В любом случае, мне все еще любопытно, когда все данные не будут прочитаны одновременно. Обязательно ли проверять, все ли данные прочитаны, и если да, читать снова? Кажется, я не могу заставить условно когда-либо бежать.

Спасибо.

1 Ответ

5 голосов
/ 11 октября 2011

Попробуйте отправить мегабайты данных по медленной ссылке.Зачем потоку нужно подождать, пока он не наберет all , прежде чем передать вызывающему что-либо из этого?Что делать, если другая сторона не закрыла соединение - там - это , на данном этапе нет понятия «все данные».

Предположим, вы открываете соединение с другим сервером и звоните BeginRead (или Read) с большим буфером, но он отправляет только 100 байтов, затем ждет вашего ответа - что вы ожидаете от NetworkStream?Никогда не дайте вам данные, потому что вы дали слишком большой буфер?Это было бы крайне контрпродуктивно.

Вы должны абсолютно не предполагать, что какой-либо поток (за возможным аргументом MemoryStream) заполнит буфер, который вы ему дадите.Возможно, что FileStream всегда будет для локальных файлов, но я бы ожидал , а не для общих файлов.

EDIT: Пример кода, который показывает, что буфер не заполняется - созданиеЗапрос HTTP 1.1 (довольно плохо:)

// 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());
    }
}
...