文件下载中遇到的二个现象,不知如何解释
发个牢骚先:搞什么,新手就不能一天写两篇以上的新手区文章!新手歧视嘛。
这篇文章是用来提问题的,所以你可能从中什么也学不到,如果浪费了你的时间,很抱歉。
二个问题
1、为什么会url直接下载>>HTTPS时下载的速度>>HTTP时下载的速度
2、400M不到的文件,下载过程中inetinfo的虚拟内存居然达到了近2G,那时客户端才下了3M不到
先描述下场景。这个页面负责文件下载,下载的文件在局域网的另一台机器上(download server),ASPX页面在web server上。在web上做了https,可以通过https或者http访问这个页面;局域网的速度10MB/s;下载的文件大小:363,895KB。
web服务器配置
最初的代码是把download server上的文件一股脑的读入内存,然后在传输到客户端。
监视了下整个下载过程
(1)任务管理器
(2)性能
我对上图的理解是,第一阶段,把远端的文件全部读入web服务器上的asp.net进程占用的内存中(文件363,895KB),在这期间CPU始终保持100%,CPU使用率之所以这么高,是由于局域网的10M速度造成(速度下降到1M时,CPU在60%上下)。
第二阶段,ASP.net的内存迅速上升(远高于文件实际大小),此时IIS进程也不甘人后,可用内存则迅速降低。在IIS的使用内存达到恒定后,客户端弹出保存对话框
第三阶段, 文件传输到客户端。cpu使用率下降,可用内存升高。
可以看出这段代码存在许多问题,尤其是在下载大文件时,ASP.net超出60%物理内存后会被回收,可用内存不够用,CPU 长时间100%。
附张局域网速度1M时的:
为了解决这些问题,试了一些方法,但都不成功。或许某人说的对,用纯.net的方案是无解的。一个的非纯.net解决方案是ISAPI Filters+HttpHandler,限于本人水平有限,写不来那个ISAPI Filters。
前话表述完了,开始说说自己遇到的几个问题
1、url直接下载>>HTTPS时下载的速度>>HTTP时下载的速度(Why)
看到别人为了解决耗内存,用了句Response.Flush()
用了下,帮助不大
(1)用HTTPS访问该页面时
客户端下载速度
性能
(2)用HTTP访问该页面时
客户端下载速度
性能
同样的代码在Https、Http访问时有不同的表现,这让我很诧异。1、下载速度差的离谱,即使是较快的https,也只有带宽的1/10;http更别提了,下了没几M,自己就停止传输了。CPU和速度还是有很大的关系,https时的持续100%,http时的5%不到。唯一的亮点是可用内存好多啊。
这里,我的问题就是为什么会url直接下载>>HTTPS时下载的速度>>HTTP时下载的速度
2、400M不到的文件,下载过程中inetinfo的虚拟内存居然达到了近2G,那时客户端才下了3M不到(Why)
换了个想法(从结果看很不成熟的想法)。开了个线程去取数据到内存里放着,主线程把这些数据传給客户端。
代码如下
using System;
namespace ComDownload
{
/// <summary>
/// ╕├└α▒ú┤µ┴╦byte╩²╫Θ╝░╞Σ╩²╫Θ╡─╘¬╦╪╕÷╩²
/// </summary>
public class ComBytes
{
private byte[] bytes;
private int size;
/// <summary>
/// ╣╣╘∞║»╩²
/// </summary>
public ComBytes(byte[] pBytes,int pSize)
{
Bytes = pBytes;
Size = pSize;
}
/// <summary>
/// byte╩²╫Θ
/// </summary>
public byte[] Bytes
{
get
{
return bytes;
}
set
{
bytes = value;
}
}
/// <summary>
/// ╩²╫Θ╡─╘¬╦╪╕÷╩²
/// </summary>
public int Size
{
get
{
return size;
}
set
{
size = value;
}
}
}
}
using System;
namespace ComDownload
{
/// <summary>
/// ╢╙┴╨╜╙┐┌
/// </summary>
public interface IQueue
{
/// <summary>
/// ┼╨╢╧╢╙┴╨╩╟╖±╥╤┬·
/// </summary>
bool IsFull();
/// <summary>
/// ┼╨╢╧╢╙┴╨╩╟╖±╬¬┐╒
/// </summary>
bool IsEmpty();
/// <summary>
/// ╟σ┐╒╢╙┴╨
/// </summary>
void Clear();
/// <summary>
/// ╚δ╢╙
/// </summary>
void In(object item);
/// <summary>
/// │÷╢╙
/// </summary>
object Out();
}
/// <summary>
/// ╤¡╗╖╦│╨≥╢╙┴╨
/// </summary>
public class CycQueue : IQueue
{
//╤¡╗╖╦│╨≥╢╙┴╨╡─╚▌┴┐
private int maxsize;
//┤µ┤ó╦│╨≥╢╙┴╨╓╨╡─╓╡
private object[] data;
//╢╙═╖
private int front;
//╢╙╬▓
private int rear;
/// <summary>
/// ╣╣╘∞╞≈
/// </summary>
public CycQueue(int size)
{
data=new object[size];
Maxsize = size;
front = rear = 0;
}
/// <summary>
/// ╚▌┴┐╩⌠╨╘
/// </summary>
public int Maxsize
{
get
{
return maxsize;
}
set
{
maxsize = value;
}
}
/// <summary>
/// ╟σ┐╒
/// </summary>
public void Clear()
{
front = rear = -1;
}
/// <summary>
/// ┼╨╢╧╢╙┴╨╩╟╖±╬¬┐╒
/// </summary>
public bool IsEmpty()
{
return front == rear;
}
/// <summary>
/// ┼╨╢╧╢╙┴╨╩╟╖±╥╤┬·
/// </summary>
public bool IsFull()
{
return (rear + 1) % Maxsize == front;
}
/// <summary>
/// ╚δ╢╙
/// </summary>
public void In(object item)
{
//╥¬╘┌IsFull()┼╨╢╧╓«╟░╝╙╦°ú¼╢α╧▀│╠╡─│í║╧ú¼┐╔─▄╘┌┼╨╢╧IsFull()=false║≤ú¼
//╓┤╨╨╞Σ╦√╧▀│╠╡─In▓┘╫≈ú¼╒Γ╤∙╘∞│╔╒Γ╕÷╧▀│╠IsFull()=trueú¼
//╢°▓╗╩╟╓«╟░╡─false┴╦
lock(this)
{
if (IsFull())
{
//╢╙┴╨┬·ú¼╩▓├┤╥▓▓╗╫÷
return;
}
data[rear] = item;
rear = (rear + 1) % Maxsize;
}
}
/// <summary>
/// //│÷╢╙
/// </summary>
public object Out()
{
object temp = null;
//╥¬╘┌IsEmpty()┼╨╢╧╓«╟░╝╙╦°ú¼╢α╧▀│╠╡─│í║╧ú¼┐╔─▄╘┌┼╨╢╧IsEmpty()=false║≤ú¼
//╓┤╨╨╞Σ╦√╧▀│╠╡─Out▓┘╫≈ú¼╒Γ╤∙╘∞│╔╒Γ╕÷╧▀│╠IsEmpty()=trueú¼
//╢°▓╗╩╟╓«╟░╡─false┴╦
lock(this)
{
if (IsEmpty())
{
return null;
}
temp = data[front];
front = (front + 1) % Maxsize;
}
return temp;
}
}
}
using System;
namespace ComDownload
{
/// <summary>
/// 该类保存了byte数组及其数组的元素个数
/// </summary>
public class ComBytes
{
private byte[] bytes;
private int size;
/// <summary>
/// 构造函数
/// </summary>
public ComBytes(byte[] pBytes,int pSize)
{
Bytes = pBytes;
Size = pSize;
}
/// <summary>
/// byte数组
/// </summary>
public byte[] Bytes
{
get
{
return bytes;
}
set
{
bytes = value;
}
}
/// <summary>
/// 数组的元素个数
/// </summary>
public int Size
{
get
{
return size;
}
set
{
size = value;
}
}
}
}
ComDownload.download process = null;
using System;
namespace ComDownload
{
/**//// <summary>
/// 队列接口
/// </summary>
public interface IQueue
{
/**//// <summary>
/// 判断队列是否已满
/// </summary>
bool IsFull();
/**//// <summary>
/// 判断队列是否为空
/// </summary>
bool IsEmpty();
/**//// <summary>
/// 清空队列
/// </summary>
void Clear();
/**//// <summary>
/// 入队
/// </summary>
void In(object item);
/**//// <summary>
/// 出队
/// </summary>
object Out();
}
/**//// <summary>
/// 循环顺序队列
/// </summary>
public class CycQueue : IQueue
{
//循环顺序队列的容量
private int maxsize;
//存储顺序队列中的值
private object[] data;
//队头
private int front;
//队尾
private int rear;
/**//// <summary>
/// 构造器
/// </summary>
public CycQueue(int size)
{
data=new object[size];
Maxsize = size;
front = rear = 0;
}
/**//// <summary>
/// 容量属性
/// </summary>
public int Maxsize
{
get
{
return maxsize;
}
set
{
maxsize = value;
}
}
/**//// <summary>
/// 清空
/// </summary>
public void Clear()
{
front = rear = -1;
}
/**//// <summary>
/// 判断队列是否为空
/// </summary>
public bool IsEmpty()
{
return front == rear;
}
/**//// <summary>
/// 判断队列是否已满
/// </summary>
public bool IsFull()
{
return (rear + 1) % Maxsize == front;
}
/**//// <summary>
/// 入队
/// </summary>
public void In(object item)
{
lock(this)
{
if (IsFull())
{
//队列满,什么也不做
return;
}
data[rear] = item;
rear = (rear + 1) % Maxsize;
}
}
/**//// <summary>
/// //出队
/// </summary>
public object Out()
{
object temp = null;
lock(this)
{
if (IsEmpty())
{
return null;
}
temp = data[front];
front = (front + 1) % Maxsize;
}
return temp;
}
}
}
using System;
using System.Threading;
using System.Net;
using System.IO;
namespace ComDownload
{
public class download
{
/**//// <summary>
/// 下载完成
/// </summary>
private bool mblnCompleted;
/**//// <summary>
/// 文件的读操作完成
/// </summary>
private bool mblnReadCompleted;
/**//// <summary>
/// 每次传递的数组长度
/// </summary>
private int mintpostlength;
/**//// <summary>
/// 循环队列的容量
/// </summary>
private const int mintMaxQueueSize = 1000;
/**//// <summary>
/// 等待时间
/// </summary>
private const int mintSleep = 5000;
/**//// <summary>
/// 队列
/// </summary>
private CycQueue queue = null;
/**//// <summary>
/// 文件URL
/// </summary>
private string mstrUrl = null;
/**//// <summary>
/// 读文件的线程
/// </summary>
private Thread getbytesThread = null;
/**//// <summary>
/// 构造函数
/// </summary>
/// <param name="PostBytesLength">
/// 每次下载字节数长度
/// </param>
/// <param name="FileUrl">
/// 文件URL
/// </param>
public download(int PostBytesLength,string FileUrl)
{
mblnCompleted = false;
mblnReadCompleted = false;
mintpostlength = PostBytesLength;
mstrUrl = FileUrl;
queue = new CycQueue(mintMaxQueueSize);
}
/**//// <summary>
/// 清理
/// </summary>
public void Close()
{
if(getbytesThread!=null)
getbytesThread.Abort();
}
/**//// <summary>
/// 判断下载是否完成
/// </summary>
public bool IsCompleted()
{
return mblnCompleted;
}
/**//// <summary>
/// 开始下载
/// </summary>
public void Start()
{
getbytesThread = new Thread(new ThreadStart(ReadBytes));
getbytesThread.Start();
}
/**//// <summary>
/// 读取远程文件
/// </summary>
private void ReadBytes()
{
Stream readStream = null;
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(mstrUrl);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
readStream = response.GetResponseStream();
byte[] bytes = new byte[mintpostlength];
int intBytesRead = 0;
ComBytes comBytes = null;
while ((intBytesRead = readStream.Read(bytes,0,mintpostlength)) > 0)
{
while(queue.IsFull())
{
Thread.Sleep(mintSleep);
}
comBytes = new ComBytes(bytes,intBytesRead);
queue.In(comBytes);
}
mblnReadCompleted = true;
}
finally
{
if(readStream!=null)
{
readStream.Close();
}
}
}
/**//// <summary>
/// 传输字节流
/// </summary>
/// <returns>ComBytes字节流</returns>
public ComBytes GetBytes()
{
if(mblnReadCompleted && queue.IsEmpty())
{
mblnCompleted = true;
return null;
}
if(queue.IsEmpty())
{
Thread.Sleep(mintSleep);
return null;
}
return (ComBytes)queue.Out();
}
}
}
ComDownload.download process = null;
try
{
process = new ComDownload.download(10240,"http://localhost:800/TestDownload/a.zip");
process.Start();
Response.ClearHeaders();
Response.AppendHeader("Content-Disposition","attachment; filename=a.zip");
Response.ContentType="application/octet-stream";
ComBytes bytes = null;
while(!process.IsCompleted())
{
bytes = process.GetBytes();
if(bytes == null)
{
continue;
}
Response.OutputStream.Write(bytes.Bytes,0,bytes.Size);
Response.Flush();
}
}
catch
{
}
finally
{
if(process!=null)
{
process.Close();
}
}
ComDownload.download process = null;
try
{
process = new ComDownload.download(10240,"http://localhost:800/TestDownload/a.zip");
process.Start();
Response.ClearHeaders();
Response.AppendHeader("Content-Disposition","attachment; filename=a.zip");
Response.ContentType="application/octet-stream";
ComBytes bytes = null;
while(!process.IsCompleted())
{
bytes = process.GetBytes();
if(bytes == null)
{
continue;
}
Response.OutputStream.Write(bytes.Bytes,0,bytes.Size);
Response.Flush();
}
}
catch
{
}
finally
{
if(process!=null)
{
process.Close();
}
}
这里依旧有url直接下载>>HTTPS时下载的速度>>HTTP时下载的速度的问题
(1)先看HTTPS
下载速度
任务管理器
(2)再看HTTP的
文件也才400M不到,为什么inetinfo的虚拟内存就占用了近2G?
参考: