使用.NET流式传输文件 - 客户端连接时间?

时间:2010-02-26 00:25:25

标签: c# logging streaming download

所以我回答了一段关于使用C#(Securing Large Downloads Using C# and 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 个答案:

答案 0 :(得分:1)

对不起,但可能无法做你想做的事。在调用Write()(在NetworkStream上)之后,数据立即被提供给Windows的套接字,后者又将数据写入网卡的缓冲区。因此,.Net不会立即执行任何缓冲和写入返回。由于.Net不缓冲NetworkStream,因此调用Flush()无效。因此,从.Net开始,不可能等到数据离开网卡的缓冲区。

即使您以某种方式设法等待数据完全离开NIC的缓冲区,也无法保证客户端始终收到数据。

答案 1 :(得分:0)

解决方案是让客户端应用程序在拥有整个文件后发送“已接收”确认数据包。一旦你收到了,你知道他们实际收到了整个东西,并且可以停止计时器。