zoukankan      html  css  js  c++  java
  • http协议多线程文件传输

          HTTP亦即Hpyer Text Transfer Protocal的缩写,它是现代互联网上最重要的一种网络协议,超文本传输协议位于TCP/IP协议的应用层,是一个面向无连接、简单、快速的C/S结构的协议。HTTP的工作过程大体上分连接、请求、响应和断开连接四个步骤。C#语言对HTTP协议提供了良好的支持,在.NET类库中提供了WebRequestWebResponse类,这两个类都包含在System.Net命名空间中,利用这两个类可以实现很多高级的网络功能,本文中多线程文件下载就是利用这两个类实现的。 WebRequestWebResponse都是抽象基类,因此在程序中不能直接作为对象使用,必须被继承,实际使用中,可根据URI参数中的URI前缀选用它们合适的子类,对于HTTP这类URI,HttpWebRequestHttpWebResponse类可以用于处理客户程序同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返回报文信息,需要使用HttpWebResponseGetResponseStream()方法,该方法返回一个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)//构造方法
     {
      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;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
       {
        
    break;
       }
      }
      fstemp.Close ();
     }
     fs.Close ();
     DateTime dt
    =DateTime.Now;
     textBox1.Text
    =dt.ToString ();//结束时间
     MessageBox.Show ("接收完毕!!!");
    }

  • 相关阅读:
    Android 优雅的让Fragment监听返回键
    Android 去掉TabLayout下的阴影,AppBarLayout下的阴影
    mongodb.conf配置文件详解
    Ubuntu14.04下Mongodb的Java API编程实例(手动项目或者maven项目)
    Ubuntu14.04下初步使用MongoDB
    如何做到Ubuntu14.04下的mongdb远程访问?(图文详解)
    Ubuntu14.04下Mongodb(在线安装方式|apt-get)安装部署步骤(图文详解)(博主推荐)
    neo4j的配置文件(图文详解)
    Ubuntu14.04下Neo4j图数据库官网安装部署步骤(图文详解)(博主推荐)
    Ubuntu16.04下Neo4j图数据库官网安装部署步骤(图文详解)(博主推荐)
  • 原文地址:https://www.cnblogs.com/linzheng/p/1944926.html
Copyright © 2011-2022 走看看