Asp.Net 上传大文件专题(1)--概述:上传大文件的难点

Asp.Net 上传大文件专题(1)--概述:上传大文件的难点

前提概要:

       本专题从今天开始主要向大家介绍如何实现Asp.Net上传大文件,写这个的目的也主要是为了学习和交流,如果大家发现任何错误,请即时指出,以免误人子弟。

本专题主要参考文章:
[1]Asp.NET大文件上传开发总结
[2]ASP.NET 应用程序生命周期概述
[3]SunriseUpload.0.9.1的源码分析(七)
[4]Http 请求处理流程
[5]使用 HtmlInputFile 服务器控件时无法上载大文件
[6]小述ASP.NET大文件上传

正文部分:

        注意:以下红色部分字体说明该内容引用于微软的相关网站

        因为要做一个视频网站,所以需要提供用户上传视频的功能。可是ASP.Net自带的上传控件只能用于上传小文件,这显然无法满足需要。有些朋友可能要问了 "为什么需要用那个呀,直接FTP传不就好了",是的,用FTP传就方便了很多,但是FTP在用户上传后,无法对上传的文件进行在线编辑(比如格式转换, 添加到数据库呀等),所有这些可以由网站自动完成的烦琐的任务则都将交由管理人员来完成,这对于一个商业网站来说无疑增加了用人成本。而且这些重复的低脑 力活的工作,看起来就和体力活没什么区别,这不又从另一个侧面降低了我们这些IT人员的价值。扯远了,言归正传,那MS为什么要将这个上传控件的能力限制 这么小呢?在MSDN以及微软的其它网站上我们可以了解到:"web.config 配置文件中的<httpRuntime> 节的 maxRequestLength 参数的默认值为 4096 (4 MB)。所以,默认情况下不能上传大于这个值的文件。这也是为了防止拒绝服务攻击。"

       可是,这样一来就对我们上传大文件造成了麻烦。有些朋友可能发现既然限制上传文件大小是由于maxRequestLength 这个参数,那将这个值改大点不就OK了。的确,这样做便可轻轻松松提高文件上传大小的限制,可是在"上传过程中,ASP.NET 首先将整个文件加载到内存中,然后用户才可以将该文件保存到磁盘。"也 就是说,如果用户上传的文件大小为100M,那么服务器的内存中就要拿出100M来存放用户上传的文件;如果是10个用户在同时上传,暂且不提并行性的问 题,那10个用户就要占用1000M的内存;如果是100、1000、甚至是几万个用户呢?那么,再大的内存都不够你拿来提供用户上传的。   

        " 另外,其他因素也会影响可以上载的最大文件大小。这些因素包括可用内存、可用硬盘空间、处理器速度和当前网络流量。对于上载的常规流量的文件, Microsoft 建议您让最大文件大小介于 10 到 20 MB 之间。如果您很少上载文件,则最大文件大小可以为 100 MB。"

        一个企业内部的视频网站,估且算它的日流量为1000人次,那么按照微软的建议,所上传的文件大小应尽量控制在20M以内,可是这样的大小还是很容易造成 服务器的瘫痪,综合考虑后,我把大小控制在6M以内(为什么在这个范围,后面会有提到,提早告诉大家,是为了让文章能连贯一点)。大家一定会奇怪“一般一 部视频大小都至少有个100~200M,小于6M的不多吧?” 是的,这个问题就是我们要解决的关键。

        在解决这个问题前,大家必须先清楚一件事,我们这里所说的文件大小"6M","200M"指的是针对服务器端而言呢,还是客户端而言呢?正确的理解如下: 200M是针对客户端用户而言的大小,一般情况下允许用户上传最大600M大小的文件(这个600M是考虑到我服务器的硬盘大小,大家可以灵活掌握,不过 一般最好不要超过1G);6M则指的是服务器端所能接收的文件大小,这样才能不让服务器的内存因为上传文件而被吞噬光。

        那么,现在我们就可以把问题转化为:如何让服务器以小于6M的大小来接收用户上传的200M视频的?

        大家是不是看得有点晕,那我拿“奥运会门票出售的情况”来举个例子。

        这几天是出售奥运会门票的最后一个阶段,为了能在最后一阶段买到门票,很多人都提早好几天等在售票窗口前。我们假设有10W人需要门票(就好像用户上传 200M的视频),理想的情况自然是开10W个窗口来出售门票(这里的窗口相当于服务器可以接收的文件大小,而10W则相当于我们将 maxRequestLength等相关元素设置很大)。可是想一想就知道,这样做是不可能的(原因自己想吧~)。那怎么解决的呢?只有将窗口数按照某种 规则限制在一定数量(比如20个),然后想买票的人排队买票。

        相信通过这个例子,有些朋友可能已经想到了如何解决我们之前的问题了。办法就是在服务器端通过某种方法将请求分组接收。

        这部分先写到这了。

        [补充] 很多朋友提出类似:"Asp.Net 2.0以上版本好像已经不全部放入内存"的意见,首先我很感谢大家的支持,发现自己的确对于这些内容掌握的还不够深入。在大家的提醒下,查阅了一些相关资料,所以再做一个补充,以免其他人和我犯一样的错误。以下内容摘自:随便说说:在ASP.NET应用程序中上传文件

    对于某些服务器端的技术,例如Spring Framework,或者早期ASP.NET 1.1时,为了供程序处理,都会将用户上传的内容完全载入内存,这的确会带来问题。但是其实协议本身并没有规定服务器端应该使用何种方式来处理上传的文 件。例如在现在的ASP.NET 2.0中就已经会在用户上传数据超过一定数量之后将其存在硬盘中的临时文件中,而这点对于开发人员完全透明,也就是说,开发人员可以像以前一样进行数据流 的处理。

  ASP.NET 2.0启用硬盘临时文件的阈值(threshold)是可配置的:

<system.web>
 <httpRuntime
    maxRequestLength="Int32"
    requestLengthDiskThreshold="Int32" />
</system.web>

   maxRequestLength自不必说,刚接触ASP.NET的朋友总会发现上传文件不能超过4M,这就是因为maxRequestLength的 大小默认为4096,这就限制着每个请求的大小不得超过4096KB。这么做的目的是为了保护应用程序不受恶意请求的危害。当请求超过 maxRequestLength之后,ASP.NET处理程序将不会处理该请求。这里和ASP.NET抛出一个异常是不同的,这就是为什么如果用户上传 文件太大,看到的并非是ASP.NET应用程序中指定的错误页面(或者默认的),因为ASP.NET还没有对这个请求进行处理。   
   requestLengthDiskThreshold就是刚才所提到的阈值,其默认值为256,即一个请求内容超过256KB时就会启用硬盘作为缓存。 这个阈值理论上和客户端是否是在上传内容无关,只要客户端发来的请求大于这个值即可。因此,在ASP.NET 2.0中服务器的内存不会因为客户端的异常请求而耗尽。

posted on 2009-04-09 21:35  starspace  阅读(306)  评论(0编辑  收藏  举报

导航