Потоковая передача файла с .NET - время подключения клиента? - PullRequest
0 голосов
/ 26 февраля 2010

Итак, я недавно задал вопрос о защите загрузок с помощью C # ( Защита больших загрузок с использованием C # и IIS 7 ), и я получил несколько полезных советов о том, как это сделать (включая чтение файла в память а потом пишет это пользователю). Единственная проблема заключается в том, что теперь, когда я пытаюсь реализовать некоторые базовые функции, я бью кирпичную стену. Вот код для потоковой передачи файла:

public void StreamFile(string file_path)
{
    DateTime start;
    TimeSpan ts;
    FileStream fstream;
    string filename = Path.GetFileName(file_path);
    byte[] buffer = new byte[STREAM_BUFFER_SIZE];
    int count = 1, total = 0, seconds;

    // Open the file to read
    fstream = new FileStream("D:\\" + file_path, FileMode.Open, FileAccess.Read);

    // Set up the response headers
    Response.AddHeader("Content-Length", fstream.Length.ToString());
    Response.AddHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
    Response.ContentType = "application/octet-stream";

    // If the user agent is Internet Explorer, we add one last header
    if (Request.UserAgent.Contains("MSIE"))
        Response.AddHeader("Content-Transfer-Encoding", "binary");

    // Start counting the time
    start = DateTime.Now;

    // Now, until the client disconnects, we stream the file
    while (Response.IsClientConnected)
    {
        // Read the file into the buffer
        count = fstream.Read(buffer, 0, buffer.Length);

        // If the buffer is empty, break out of the loop. We're done!
        if (count == 0)
            break;

        // Write to the output stream and push it to the user
        Response.OutputStream.Write(buffer, 0, count);
        Response.Flush();

        // Increment the total as well, this way we can know how much we've streamed
        total += count;
    }
    // The transfer is done! Close the connection.
    Response.Close();

    // Count the number of seconds
    ts = DateTime.Now - start;
    seconds = ts.Seconds + (60 * ts.Minutes) + (60 * 60 * ts.Hours); // Also, is there a better way to do this? This is laaaaaame!

    // Finally, log the transfer
    Logging.AddLog(Request["user"], file_path, total, count == 0, seconds);
}

Хорошо, проблема в том, что записи журнала, которые он создает, говорят, что файл завершился за то количество секунд, которое потребовалось для чтения файла в память, а не для его загрузки пользователем. Я предполагаю, что Response.ClientConnected позаботится об этом, но, видимо, нет. Таким образом, время загрузки файла, как сообщается в журналах, составляет 0-1 секунду, и даже когда я прекращаю загрузку на полпути, в журналах сообщается, что все это предоставлено.

Кто-нибудь делал что-то подобное раньше, или есть идеи, как я могу получить РЕАЛЬНЫЕ номера за переводом? К сожалению, наличие этой информации является огромным приоритетом, или я бы просто отмахнулся от нее и вообще удалил эти два значения из журнала.

Ответы [ 2 ]

1 голос
/ 28 февраля 2010

Извините, но, вероятно, невозможно сделать то, что вы хотите. После вызова Запись () (на NetworkStream ) данные немедленно передаются в сокеты Windows, которые, в свою очередь, записывают данные в буфер сетевой карты. Итак, .Net не выполняет буферизацию и запись немедленно возвращается. Поскольку NetworkStream не буферизируется .Net, вызов Flush () не имеет никакого эффекта. Поэтому из .Net невозможно дождаться, пока данные не покинут буфер сетевой карты.

Даже если вам каким-то образом удалось подождать, пока данные не покинут буфер NIC, нет никакой гарантии, что клиент когда-либо получал данные.

0 голосов
/ 28 февраля 2010

Решение состоит в том, чтобы ваше клиентское приложение отправляло пакет подтверждения «Получено» обратно, как только у него будет весь файл. Получив это, вы знаете, что они действительно получили все это, и можете остановить таймер.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...