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

用C#实现HTTP协议下的多线程文件传输
转自  http://developer.51cto.com/art/201105/263066_all.htm

C#(C Sharp)是微软(Microsoft)为.NET Framework量身订做的程序语言,C#拥有C/C++的强大功能以及Visual Basic简易使用的特性,是第一个组件导向(Component-oriented)的程序语言,和C++与Java一样亦为对象导向(object-oriented)程序语言。下面主要介绍的是用C#实现HTTP协议下的多线程文件传输。

很多人都有过使用网络蚂蚁或网络快车软件下载互联网文件的经历,这些软件的使用可以大大加速互联网上文件的传输速度,减少文件传输的时间。这些软件为什么有如此大的魔力呢?

其主要原因是这些软件都采用了多线程下载和断点续传技术。如果我们自己来编写一个类似这样的程序,也能够快速的在互联网上下载文件,那一定是非常愉快的事情。下面我就讲一讲如何利用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 设计好的窗口。

控件定义代码是:

 1     public System.Windows.Forms.ListBox listBox1;
 2     private System.Windows.Forms.Label label1;
 3     private System.Windows.Forms.TextBox textBox1
 4     private System.Windows.Forms.Button button1;
 5     private System.Windows.Forms.Label label2;
 6     private System.Windows.Forms.TextBox textBox2;
 7     private System.Windows.Forms.Label label3;
 8     private System.Windows.Forms.TextBox textBox3;
 9     private System.Windows.Forms.Label label4;
10     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类,用于管理接收线程,其代码如下:

  1 public class HttpFile
  2     {
  3      public Form1 formm;
  4      public int threadh;//线程代号
  5      public string filename;//文件名
  6      public string strUrl;//接收文件的URL
  7      public FileStream fs;
  8      public HttpWebRequest request;
  9      public System.IO.Stream ns;
 10      public byte[] nbytes;//接收缓冲区
 11      public int nreadsize;//接收字节数
 12      public HttpFile(Form1 form,int thread)//构造方法
 13      {
 14     formm=form;
 15     threadh=thread;
 16      }
 17      ~HttpFile()//析构方法
 18      {
 19     formm.Dispose ();
 20      }
 21      public void receive()//接收线程
 22      {
 23     filename=formm.filenamew[threadh];
 24     strUrl=formm.strurl;
 25     ns=null;
 26     nbytes= new byte[512];
 27     nreadsize=0;
 28     formm.listBox1 .Items .Add ("线程"+threadh.ToString ()+"开始接收");
 29     fs=new FileStream (filename,System.IO.FileMode.Create);
 30     try
 31     {
 32      request=(HttpWebRequest)HttpWebRequest.Create (strUrl);
 33      //接收的起始位置及接收的长度
 34      request.AddRange(formm.filestartw [threadh],
 35      formm.filestartw [threadh]+formm.filesizew [threadh]);
 36      ns=request.GetResponse ().GetResponseStream ();//获得接收流
 37      nreadsize=ns.Read (nbytes,0,512);
 38      while (nreadsize>0)
 39      {
 40     fs.Write (nbytes,0,nreadsize);
 41     nreadsize=ns.Read (nbytes,0,512);
 42     formm.listBox1 .Items .Add ("线程"+threadh.ToString ()+"正在接收");
 43      }
 44      fs.Close();
 45      ns.Close ();
 46     }
 47     catch (Exception er)
 48     {
 49      MessageBox.Show (er.Message );
 50      fs.Close();
 51     }
 52     formm.listBox1 .Items.Add ("进程"+threadh.ToString ()+"接收完毕!");
 53     formm.threadw[threadh]=true;
 54      }}
 55
 56 该类和Form1类处于统一命名空间,但不包含在Form1类中。下面定义“开始接收”按钮控件的事件响应函数:
 57
 58     private void button1_Click(object sender, System.EventArgs e)
 59     {
 60      DateTime dt=DateTime.Now;//开始接收时间
 61      textBox1.Text =dt.ToString ();
 62      strurl=textBox2.Text .Trim ().ToString ();
 63      HttpWebRequest request;
 64      long filesize=0;
 65      try
 66      {
 67     request=(HttpWebRequest)HttpWebRequest.Create (strurl);
 68     filesize=request.GetResponse ().ContentLength;//取得目标文件的长度
 69     request.Abort ();
 70      }
 71      catch (Exception er)
 72      {
 73     MessageBox.Show (er.Message );
 74      }
 75      // 接收线程数
 76      thread=Convert.ToInt32 (textBox4.Text .Trim().ToString (),10);
 77      //根据线程数初始化数组
 78      threadw=new bool [thread];
 79      filenamew=new string [thread];
 80      filestartw=new int [thread];
 81      filesizew=new int[thread];
 82
 83      //计算每个线程应该接收文件的大小
 84      int filethread=(int)filesize/thread;//平均分配
 85      int filethreade=filethread+(int)filesize%thread;//剩余部分由最后一个线程完成
 86      //为数组赋值
 87      for (int i=0;i<thread;i++)
 88      {
 89     threadw[i]=false;//每个线程状态的初始值为假
 90     filenamew[i]=i.ToString ()+".dat";//每个线程接收文件的临时文件名
 91     if (i<thread-1)
 92     {
 93      filestartw[i]=filethread*i;//每个线程接收文件的起始点
 94      filesizew[i]=filethread-1;//每个线程接收文件的长度
 95     }
 96     else
 97     {
 98      filestartw[i]=filethread*i;
 99      filesizew[i]=filethreade-1;
100     }
101      }
102      //定义线程数组,启动接收线程
103      Thread[] threadk=new Thread [thread];
104      HttpFile[] httpfile=new HttpFile [thread];
105      for (int j=0;j<thread;j++)
106      {
107     httpfile[j]=new HttpFile(this,j);
108     threadk[j]=new Thread(new ThreadStart (httpfile[j].receive ));
109     threadk[j].Start ();
110      }
111      //启动合并各线程接收的文件线程
112      Thread hbth=new Thread (new ThreadStart (hbfile));
113      hbth.Start ();
114     }

合并文件的线程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-12-05 02:40:54

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

Linux下几种文件传输命令

Linux下几种文件传输命令 sz rz sftp scp 最近在部署系统时接触了一些文件传输命令,分别做一下简单记录: 1.sftp Secure Ftp 是一个基于SSH安全协议的文件传输管理工具.由于它是基于SSH的,会在传输过程中对用户的密码.数据等敏感信息进行加密,因此可以有效的防止用户信息在传输的过程中被窃取,比FTP有更高的安全性.在功能方面与FTP很类似,不仅可以传输文件数据,而且可以进行远程的文件管理(如建立,删除,查看文件列表等操作).Sftp与ftp虽然只有一字之差,但基于

[原创] Linux下几种文件传输命令 sz rz sftp scp介绍

Linux下几种文件传输命令 sz rz sftp scp介绍 1.sftp Secure Ftp 是一个基于SSH安全协议的文件传输管理工具.由于它是基于SSH的,会在传输过程中对用户的密码.数据等敏感信息进行加密,因此可以有效的防止用户信息在传输的过程中被窃取,比FTP有更高的安全性.在功能方面与FTP很类似,不仅可以传输文件数据,而且可以进行远程的文件管理(如建立,删除,查看文件列表等操作).Sftp与ftp虽然只有一字之差,但基于的传输协议却是不同的.因此不能用sftp client去连

[转帖]Linux下主机间文件传输命令

Linux下主机间文件传输命令 https://yq.aliyun.com/articles/53631?spm=a2c4e.11155435.0.0.580ce8ef4Q9uzs SCP命令: 简介: scp 命令在网络上的主机之间拷贝文件,它是安全拷贝(secure copy)的缩写. scp 命令使用 ssh 来传输数据,并使用与 ssh 相同的认证模式,提供同样的安全保障. 如果有公钥打通就不用密码,如果没有就会提示输入密码. 用法: 1 #Copy 本地文件 /etc/eva.log,

Linux菜鸟成长日记 ( Linux 下的 ftp 文件传输协议 )

https://blog.csdn.net/buster_zr/article/details/80244542 FTP FTP 是 File Transfer Protocol (文件传输协议)的英文简称,而中文简称为"文传协议".用于Internet上的控制文件的双向传输.同时,它也是一个应用程序(Application).基于不同的操作系统有不同的FTP应用程序,而所有这些应用程序都遵守同一种协议以传输文件.在FTP的使用当中,用户经常遇到两个概念:"下载"(

Linux下几种文件传输命令 sz rz sftp scp

最近在部署系统时接触了一些文件传输命令,分别做一下简单记录: 1.sftp Secure Ftp 是一个基于SSH安全协议的文件传输管理工具.由于它是基于SSH的,会在传输过程中对用户的密码.数据等敏感信息进行加密,因此可以有效的防止用户信息在传输的过程中被窃取,比FTP有更高的安全性.在功能方面与FTP很类似,不仅可以传输文件数据,而且可以进行远程的文件管理(如建立,删除,查看文件列表等操作).Sftp与ftp虽然只有一字之差,但基于的传输协议却是不同的.因此不能用sftp client去连接

Linux下常用的文件传输方式介绍与比较

参考链接:http://mingxinglai.com/cn/2014/03/copy-file-in-linux/ 本文介绍了linux之间传输文件的几种方式,并通过具体实验测试了几种文件传输方式之间的传输速度.这篇文章是我一次作业的实验报告,我经常查看这个文档,所以贴出来方便自己查略. ###0. 实验环境以及实验数据 实验环境: 两台装有Ubuntu的电脑,两台电脑位于同一个局域网中,传输速度约4.1MB/s. 实验数据: 使用MySQL的日志文件(ib_logfile0)进行测试,日志文

Linux下几种文件传输命令 sz rz sftp scp 对比

1. sftp Secure Ftp 是一个基于SSH安全协议的文件传输管理工具.由于它是基于SSH的,会在传输过程中对用户的密码.数据等敏感信息进行加密,因此可以有效的防止用户信息在传输的过程中被窃取,比FTP有更高的安全性.在功能方面与FTP很类似,不仅可以传输文件数据,而且可以进行远程的文件管理(如建立,删除,查看文件列表等操作).Sftp与ftp虽然只有一字之差,但基于的传输协议却是不同的.因此不能用sftp client去连接ftp server 也不能用 ftp client 去连接

[文档和源码分享] 基于QT和websocket协议的多线程文件传输

做两个程序,实现文件收发 发送端放两个按钮,点击后打开电脑目录选择所要传输的文件,选好以后,把文件名和路径显示在界面上,点击第二个按钮,把文件传到远程机器(或者虚拟机)上由接收端接收 编写一接收端,把文件接收下来,存进指定的某个目录里 要能测试通过三个发送端同时发100M的文件,接收端能分别接收 使用多线程实现 Qt开发环境 websocket传输协议库 Win10_x64 参考博文和源码下载地址: https://www.write-bug.com/article/1275.html 原文地址

在Http协议下实现多线程断点的下载

0.使用多线程下载会提升文件下载的速度,那么多线程下载文件的过程是: (1)首先获得下载文件的长度,然后设置本地文件的长度 HttpURLConnection.getContentLength(); RandomAccessFile file = new RandomAccessFile("QQWubiSetup.exe","rwd"); file.setLength(filesize);//设置本地文件的长度 (2)根据文件长度和线程数计算每条线程下载的数据长度和