用C#实现HTTP协“.NET技术”议下的多线程文件传输

  很多人都有过使用网络蚂蚁或网络快车软件下载互联网文件的经历,这些软件的使用可以大大加速互联网上文件的传输速度,减少文件传输的时间。这些软件为什么有如此大的魔力呢?其主要原因是这些软件都采用了多线程下载和断点续传技术。如果我们自己来编写一个类似这样的程序,也能够快速的在互联网上下载文件,那一定是非常愉快的事情。下面我就讲一讲如何利用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返回的报文,如:首先定义一个Stream对象 public System.IO.Stream ns; 然后 ns=hwr.GetResponse ().GetResponseStream (); 即可创建Stream对象。

  有了以上的准备知识后下面开始设计我们的多线程互联网文件的下载程序,首先打开Visual Studio.Net集成开发环境,选择文件、新建、项目,然后选择Visual C#项目,在向导右边列表框中选中Windows应用程序,输入项目名称,如本例为:httpftp, 然后选择确定按钮,向导自动生成了一个Windows应用程序项目。首先打开窗口设计器设计应用程序窗口,增加如下控件:

  一个列表框 listBox1,  三个文本标签 label1-label3, 三个文本框 textBox1-textBox3, 一个开始接收按钮 button1。

  控件定义代码是:


public System.Windows.Forms.ListBox listBox1;
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上海网站建设an style="color: #000000;"> thread;//进程数

  定义一个HttpFile类,用于管理接收线程,其代码如下:


public class HttpFile{ 
public Form1 formm; 
public int threadh;//线程代号 
public上海企业网站设计与制作"color: #000000;"> 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)//构造方法 {  
formm=form;  
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 );
   fs.Close();
  }
  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<thread;i++)
 {
  threadw[i]=false;//每个线程状态的初始值为假
  filenamew[i]=i.ToString ()+".dat";//每个线程接收文件的临时文件名
  if (i<thread-1)
  {
   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<thread;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<thread;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:\\test\\httpftp\\bin\\d.htm,因\后的字符在C#中是转义字符,线程数并非越大越好,一般5个线程就可以了,该程序在Visual Studio.Net 2002开发环境及Windows xp 操作系统上通过。

时间: 2024-08-05 10:03:56

用C#实现HTTP协“.NET技术”议下的多线程文件传输的相关文章

一起谈.NET技术,用C#实现HTTP协议下的多线程文件传输

很多人都有过使用网络蚂蚁或网络快车软件下载互联网文件的经历,这些软件的使用可以大大加速互联网上文件的传输速度,减少文件传输的时间.这些软件为什么有如此大的魔力呢?其主要原因是这些软件都采用了多线程下载和断点续传技术.如果我们自己来编写一个类似这样的程序,也能够快速的在互联网上下载文件,那一定是非常愉快的事情.下面我就讲一讲如何利用C#语言编写一个支持多线程下载文件的程序,你会看到利用C#语言编写网络应程序是多么的容易,从中也能体会到C#语言中强大的网络功能. 首先介绍一下HTTP协议,HTTP亦

谈谈Python协程技术的演进

一.引言 1. 存储器山 存储器山是 Randal Bryant 在<深入理解计算机系统>一书中提出的概念. 基于成本.效率的考量,计算机存储器被设计成多级金字塔结构,塔顶是速度最快.成本最高的 CPU 内部的寄存器(一般几 KB)与高速缓存,塔底是成本最低.速度最慢的广域网云存储(如百度云免费 2T ) 存储器山的指导意义在于揭示了良好设计程序的必要条件是需要有优秀的局部性: 时间局部性:相同时间内,访问同一地址次数越多,则时间局部性表现越佳; 空间局部性:下一次访问的存储器地址与上一次的访

超线程多核心下Java多线程编程技术分析

一.Java环境下的多线程技术 构建线程化的应用程序往往会对程序带来重要的性能影响.例如,请考虑这样一个程序,它从磁盘读取大量数据并且在把它们写到屏幕之前处理这些数据(例如一个DVD播放器).在一个传统的单线程程序(今天所使用的大多数客户端程序)上,一次只有一个任务执行,每一个这些活动分别作为一个序列的不同阶段发生.只有在一块已定义大小的数据读取完成时才能进行数据处理.因此,能处理数据的程序逻辑直到磁盘读操作完成后才得到执行.这将导致非常差的性能问题. 在一个多线程程序中,可以分配一个线程来读取

IBM将收购大文件传输技术公司Aspera 布局大数据

12月20日消息,据国外http://www.aliyun.com/zixun/aggregation/31646.html">媒体报道,IBM周四宣布,将收购私有化大文件传输技术公司Aspera.但有关双方公司的交易细节信息未公布. IBM表示,Aspera的文件传输技术将会成为公司旗下未来大数据战略的关键组成. Aspera的技术能让较大规模的文档数据以较快速率传输--如通常需要26小时将一份体积为24GB的文档传输至世界的另一端,而Aspera能做到只需30秒.Aspera将其技术命

link环境下制作一款《订餐软件》,报单完成,但是缺协单的情况下,请问协单递补怎么实现?

问题描述 link环境下制作一款<订餐软件>,报单完成,但是缺协单的情况下,请问协单递补怎么实现? link环境下制作一款<订餐软件>,报单完成,但是缺协单的情况下,请问协单递补怎么实现? 解决方案 这个你可以根据时间排序,把后面的单子递补上来.

link环境下如何根据文件上传时间计算文件有效期,使用codefirst技术制作《网盘软件》

问题描述 link环境下如何根据文件上传时间计算文件有效期,使用codefirst技术制作<网盘软件> link环境下如何根据文件上传时间计算文件有效期,使用codefirst技术制作<网盘软件> 解决方案 你的有效期是固定的么? 可以用DateTime.Now.AddDays(7);,假设7天有效期. 解决方案二: 这个应该是在前台页面aspx中控制隐藏还是显示,或者在数据库中获得筛选好的文件列表给页面. 然后前台页面收到数据库,可以按照网格模式或者列表模式显示.

link环境下制作网盘,使用的是codefirst技术,请问如何制作文件删除确认功能?

问题描述 link环境下制作网盘,使用的是codefirst技术,请问如何制作文件删除确认功能? link环境下制作网盘,使用的是codefirst技术,请问如何制作文件删除确认功能? 解决方案 这属于前端的功能了,用extjs easyui等等,都有消息框的实现. 或者用confirm js函数

android-小白请教高手问题,今天看了持久化技术的关于一个从文件中读取数据的问题

问题描述 小白请教高手问题,今天看了持久化技术的关于一个从文件中读取数据的问题 想要完成一个功能,向EditText里输入数据,数据存放在一个文件夹后,然后按下back键,再重新启动这个程序,再从这个文件里读取数据,出现的是这个数据已经填充在EditText里 下面是代码 MainActivity import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileInputStream; import

【技术贴】删除空白文件夹,提示无法读源文件或磁盘的解决方法

DEL /F /A /Q \\?\%1 RD /S /Q \\?\%1 使用方法:  新建文本文档,将上面代码复制其中,保存为1.bat.不用打开此bat文件,只需要 将不能删除的文件和文件夹拖入此1.bat文件就可以删除了! [技术贴]删除空白文件夹,提示无法读源文件或磁盘的解决方法 转自百度知道.