C#实现http协议下的多线程文件传输

2020/4/22

一个列表框 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的代码编辑器,增加如下的命名空间:

sing 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)//构造方法  
      {  
     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 ("接收完毕!!!");  
    }