主页 › 博客 ›
【ASP.net 文档】用C#实现HTTP 协议下的多线程文件传输
作者: chclvzxx (1 篇文章) 日期: 五月 4, 2011 在 11:25 上午
很多人都有过使用网络蚂蚁或网络快车软件下载互联网文件的经历,这些软件的使用可以大大加速互联网上文件的传输速度,减少文件传输的时间。这些软件为什么有如此大的魔力呢?其主要原因是这些软件都采用了多线程下载和断点续传技术。如果我们自己来编写一个类似这样的程序,也能够快速的在互联网上下载文件,那一定是非常愉快的事情。下面我就讲一讲如何利用C#语言编写一个支持多线程下载文件的程序,你会看到利用C#语言编写网络应程序是多么的容易,从中也能体会到C#语言中强大的网络功能。
首先介绍一下HTTP 协议,HTTP 亦即Hpyer Text Transfer Protocal 的缩写,它是现代互联网上最重要的一种网络协议,超文本传输协议位于TCP/IP 协议的应用层,是一个面向无连接、简单、快速的C/S 结构的协议。HTTP 的工作过程大体上分连接、请求、响应和断开连接四个步骤。C#语言对HTTP 协议提供了良好的支持,在.NET 类库中提供了WebRequest 和WebResponse 类,这两个类都包含在System.Net 命名空间中,利用这两个类可以实现很多高级的网络功能,本文中多线程文件下载就是利用这两个类实现的。 WebRequest 和
WebResponse 都是抽象基类,因此在程序中不能直接作为对象使用,必须被继承,实际使用中,可根据URI 参数中的URI 前缀选用它们合适的子类,对于HTTP 这类URI,HttpWebRequest 和HttpWebResponse 类可以用于处理客户程序同WEB 服务器之间的HTTP 通讯。
HttpWebRequest 类实现了很多通过HTTP 访问WEB 服务器上文件的高级功能。HttpWebRequest 类对WebRequest 中定义的属性和方法提供支持,HttpWebRequest 将发送到Internet 资源的公共HTTP 标头的值公开为属性,由方法或系统设置,常用的由属性或方法设置的HTTP 标头为:接受, 由Accept 属性设置, 连接, 由Connection 属性和KeepAlive 属性设置, Content-Length, 由ContentLength 属性设置, Content-Type, 由ContentType 属性设置, 范围, 由AddRange 方法设置. 实际使用中是将标头信息正确设置后,传递到WEB 服务器,WEB 服务器根据要求作出回应。
HttpWebResponse 类继承自WebResponse 类,专门处理从WEB 服务器返回的HTTP 响应,这个类实现了很多方法,具有很多属性,可以全面处理接收到的互联息。在HttpWebResponse 类中,对于大多数通用的HTTP 标头字段,都有的属性与其对应,程序员可以通过这些属性方便的访问位于HTTP 接收报文标头字段中的信息,本例中用到的HttpWebResponse 类属性为:ContentLength 既接收内容的长度。
有了以上的了解后,下面看看这两个类的用法,要创建HttpWebRequest 对象,不要直接使用HttpWebRequest 的构造函数,而要使用WebRequest.Create 方法初始化一个HttpWebRequest 实例,如:
HttpWebRequest hwr=(HttpWebRequest)WebRequest.Create(http://www.163.com/);
创建了这个对象后,就可以通过HttpWebRequest 属性,设置很多HTTP 标头字段的内容,如hwr.AddRange(100,1000);设置接收对象的范围为100-1000字节。
HttpWebReques 对象使用GetResponse()方法时,会返回一个HttpWebResponse 对象,为提出HTTP 返回报文信息,需要使用HttpWebResponse 的GetResponseStream()方法,该方法返回一个Stream 对象,可以读取HTTP 返回的报文,如:首先定义一个Strean 对象 public System.IO.Stream ns; 然后 ns=hwr.GetResponse ().GetResponseStream ();即可创建Stream 对象。有了以上的准备知识后下面开始设计我们的多线程互联网文件的下载程序,首先打开Visual Studio.Net 集成开发环境,选择“文件”、“新建”、“项目”,然后选择“Visual C#项目”,在向导右边列表框中选中“Windows 应用程序”,输入项目名称,如本例为:httpftp,然后选择“确定”按钮,向导自动生成了一个Windows 应用程序项目。首先打开窗口设计器设计应用程序窗口,增加如下控件:
一个列表框 listBox1 三个文本标签 label1-label3 三个文本框 textBox1-textBox3 一个开始接收按钮 button1 设计好的窗口如下图:
控件定义代码是:
Share
private System.Windows.Forms.Label label1;
private System.Windows.Forms.TextBox textBox1
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.TextBox textBox2;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.TextBox textBox3;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.TextBox textBox4;
打开Form1的代码编辑器,增加如下的命名空间:using System.Net;//网络功能
using System.IO;//流支持
using System.Threading ;//线程支持
增加如下的程序变量:
public bool[] threadw; //每个线程结束标志
public string[] filenamew;//每个线程接收文件的文件名public int[] filestartw;//每个线程接收文件的起始位置
public int[] filesizew;//每个线程接收文件的大小
public string strurl;//接受文件的URL
public bool hb;//文件合并标志
public int thread;//进程数
定义一个HttpFile类,用于管理接收线程,其代码如下:public class HttpFile
{
public Form1 formm;
public int threadh;//线程代号
public string filename;//文件名
public string strUrl;//接收文件的URL
public FileStream fs;
public HttpWebRequest request;
public System.IO.Stream ns;
public byte[] nbytes;//接收缓冲区
public int nreadsize;//接收字节数
public HttpFile(Form1 form,int thread)//构造方法
{threadh=thread;
}
~HttpFile()//析构方法
{
formm.Dispose ();
}
public void receive()//接收线程
{
filename=formm.filenamew[threadh];
strUrl=formm.strurl;
ns=null;
nbytes= new byte[512];
nreadsize=0;
formm.listBox1 .Items .Add ("线程"+threadh.ToString ()+"开始接收");
fs=new FileStream (filename,System.IO.FileMode.Create);
try
{
request=(HttpWebRequest)HttpWebRequest.Create (strUrl);
//接收的起始位置及接收的长度
request.AddRange(formm.filestartw [threadh],
formm.filestartw [threadh]+formm.filesizew [threadh]);
ns=request.GetResponse ().GetResponseStream ();//获得接收流
nreadsize=ns.Read (nbytes,0,512);
while (nreadsize>0)
{
fs.Write (nbytes,0,nreadsize);
nreadsize=ns.Read (nbytes,0,512);
formm.listBox1 .Items .Add ("线程"+threadh.ToString ()+"正在接收");
}
fs.Close();
ns.Close ();
}
catch (Exception er)
{
MessageBox.Show (er.Message );}
formm.listBox1 .Items.Add ("进程"+threadh.ToString ()+"接收完毕!");
formm.threadw[threadh]=true;
}
}
该类和Form1类处于统一命名空间,但不包含在Form1类中。下面定义“开始接收”按钮控件的事件响应函数:private void button1_Click(object sender, System.EventArgs e)
{
DateTime dt=DateTime.Now;//开始接收时间
textBox1.Text =dt.ToString ();
strurl=textBox2.Text .Trim ().ToString ();
HttpWebRequest request;
long filesize=0;
try
{
request=(HttpWebRequest)HttpWebRequest.Create (strurl);
filesize=request.GetResponse ().ContentLength;//取得目标文件的长度
request.Abort ();
}
catch (Exception er)
{
MessageBox.Show (er.Message );
}
// 接收线程数
thread=Convert.ToInt32 (textBox4.Text .Trim().ToString (),10);
//根据线程数初始化数组
threadw=new bool [thread];
filenamew=new string [thread];
filestartw=new int [thread];
filesizew=new int[thread];
//计算每个线程应该接收文件的大小
int filethread=(int)filesize/thread;//平均分配
int filethreade=filethread+(int)filesize%thread;//剩余部分由最后一个线程完成
//为数组赋值
for (int i=0;i filestartw[i]=filethread*i;//每个线程接收文件的起始点 filesizew[i]=filethread-1;//每个线程接收文件的长度 } else { filestartw[i]=filethread*i; filesizew[i]=filethreade-1; } } //定义线程数组,启动接收线程 Thread[] threadk=new Thread [thread]; HttpFile[] httpfile=new HttpFile [thread]; for (int j=0;j httpfile[j]=new HttpFile(this,j); threadk[j]=new Thread(new ThreadStart (httpfile[j].receive )); threadk[j].Start (); } //启动合并各线程接收的文件线程 Thread hbth=new Thread (new ThreadStart (hbfile)); hbth.Start (); } 合并文件的线程hbfile定义在Form1类中,定义如下: public void hbfile() { while (true)//等待 { hb=true; for (int i=0;i if (threadw[i]==false)//有未结束线程,等待hb=false; Thread.Sleep (100); break; } } if (hb==true)//所有线程均已结束,停止等待, { break; } } FileStream fs;//开始合并 FileStream fstemp; int readfile; byte[] bytes=new byte[512]; fs=new FileStream (textBox3.Text .Trim ().ToString (),System.IO.FileMode.Create); for (int k=0;k0) { fs.Write (bytes,0,readfile); } else { break; } } fstemp.Close (); } fs.Close (); DateTime dt=DateTime.Now; textBox1.Text =dt.ToString ();//结束时间 MessageBox.Show ("接收完毕!!!"); } 至此,一个多线程下载文件的程序就大功告成了,注意在输入本地文件名时,应按如下格式输入:“c:\\\est\\\\httpftp\\\\bin\\\\d.htm”,因”\\”后的字符在C#中是转义字符,线程数并非越大越好,一般5个线程就可以了,该程序在Visual Studio.Net 2002开发环境及Windows xp 操作系统上通过。 分类:博客征文专栏, 并行计算 如需了解英特尔软件产品相关的性能和优化选项,请参阅优化注意事项. 评论 (10) 2011年05月11日 02:45 smallheant 看不太懂 2011年05月11日 18:45 嗷嗷叫的老马这些软件为什么有如此大的魔力呢?其主要原因是这些软件都采用了多线程下载和断点续传技术。// 使用多线程下载能提高速度的原因是,网站对于单个连接的速度进行了,比如10K;因此同时建立10个连接进行下载,每个连接10K,则可以达到100K了. 由于每个连接的管理需要一个线程,所以才是多线程. 如果网站对于单个连接的下载速度得比用户的下行带宽要多,则多线程下载就没有什么效果了:) 2011年05月11日 20:17 制作 什么东西????? 2011年05月12日 15:19 数据采集 还行基本功能实现不过还有进步的空间:) 2011年05月12日 20:10 synest vs2002 是亮点不错不错 2011年05月16日 05:23 胡华彬 试一下,基本功能实现 2011年05月17日 16:46 xcd333 2011年05月19日 00:40 Visual Studio.Net 2002开发环境? ap 看一下下。还可以。 2011年05月19日 00:46 软件技术论坛 我的神...现在是11年了,我看到您的在visual studio .NET 2002下通过....您就舍不得更新啊 2011年05月19日 00:49 jayboy 引用 (0) 写评论 欲获得技术支持,请访问软件支持页面.