天天看点

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对象。

代码  

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)//构造方法  

 {  

  formformm=form;  

  threadthreadh=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 filethreadfilethreade=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;k<thread;k++)  

  fstemp=new FileStream (filenamew[k],System.IO.FileMode .Open);  

  while (true)  

   readfile=fstemp.Read (bytes,0,512);  

   if (readfile>0)  

    fs.Write (bytes,0,readfile);  

   else  

  fstemp.Close ();  

 fs.Close ();  

 DateTime dt=DateTime.Now;  

 textBox1.Text =dt.ToString ();//结束时间  

 MessageBox.Show ("接收完毕!!!");  

本文转自linzheng 51CTO博客,原文链接:http://blog.51cto.com/linzheng/1079266

继续阅读