用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 设计好的窗口。
控件定义代码是:
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 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[];
nreadsize=;
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,,);
while (nreadsize>)
{
fs.Write (nbytes,,nreadsize);
nreadsize=ns.Read (nbytes,,);
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=;
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 (),);
//根据线程数初始化数组
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=;i<thread;i++)
{
threadw[i]=false;//每个线程状态的初始值为假
filenamew[i]=i.ToString ()+".dat";//每个线程接收文件的临时文件名
if (i<thread-)
{
filestartw[i]=filethread*i;//每个线程接收文件的起始点
filesizew[i]=filethread-;//每个线程接收文件的长度
}
else
{
filestartw[i]=filethread*i;
filesizew[i]=filethreade-;
}
}
//定义线程数组,启动接收线程
Thread[] threadk=new Thread [thread];
HttpFile[] httpfile=new HttpFile [thread];
for (int j=;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=;i<thread;i++)
{
if (threadw[i]==false)//有未结束线程,等待
{
hb=false;
Thread.Sleep ();
break;
}
}
if (hb==true)//所有线程均已结束,停止等待,
{
break;
}
}
FileStream fs;//开始合并
FileStream fstemp;
int readfile;
byte[] bytes=new byte[];
fs=new FileStream (textBox3.Text .Trim ().ToString (),System.IO.FileMode.Create);
for (int k=;k0)
{
fs.Write (bytes,,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 操作系统上通过。
C#实现http协议下的多线程文件传输的更多相关文章
-
Linux下几种文件传输命令
Linux下几种文件传输命令 sz rz sftp scp 最近在部署系统时接触了一些文件传输命令,分别做一下简单记录: 1.sftp Secure Ftp 是一个基于SSH安全协议的文件传输管理工具 ...
-
Linux下几种文件传输命令 sz rz sftp scp
Linux下几种文件传输命令 sz rz sftp scp 最近在部署系统时接触了一些文件传输命令,分别做一下简单记录: 1.sftp Secure Ftp 是一个基于SSH安全协议的文件传输管理工具 ...
-
[原创] Linux下几种文件传输命令 sz rz sftp scp介绍
Linux下几种文件传输命令 sz rz sftp scp介绍 1.sftp Secure Ftp 是一个基于SSH安全协议的文件传输管理工具.由于它是基于SSH的,会在传输过程中对用户的密码.数据等 ...
-
[转帖]Linux下主机间文件传输命令
Linux下主机间文件传输命令 https://yq.aliyun.com/articles/53631?spm=a2c4e.11155435.0.0.580ce8ef4Q9uzs SCP命令: ...
-
Linux菜鸟成长日记 ( Linux 下的 ftp 文件传输协议 )
https://blog.csdn.net/buster_zr/article/details/80244542 FTP FTP 是 File Transfer Protocol (文件传输协议)的英 ...
-
Linux下常用的文件传输方式介绍与比较
参考链接:http://mingxinglai.com/cn/2014/03/copy-file-in-linux/ 本文介绍了linux之间传输文件的几种方式,并通过具体实验测试了几种文件传输方式之 ...
-
Socket方法LAN多线程文件传输
1.思维:为了实现各种文件的大小可以被发送和接收的,它可以被设置为发送和接收缓冲器环.并记录文件的位置读取,假设读入缓冲区的字节的特定数目大于缓冲区的大小较小.然后该文件被发送,退出发送周期,关闭连接 ...
-
Linux下聊天和文件传输软件
全平台聊天软件 米聊 官网地址: http://www.miliao.com 潮信 官网地址: https://www.chaoxin.com
-
简单实现TCP下的大文件高效传输
简单实现TCP下的大文件高效传输 在TCP下进行大文件传输不象小文件那样直接打包个BUFFER发送出去,因为文件比较大所以不可能把文件读到一个BUFFER发送出去.主要有些文件的大小可能是1G,2G或 ...
随机推荐
-
Monte Carlo Approximations
准备总结几篇关于 Markov Chain Monte Carlo 的笔记. 本系列笔记主要译自A Gentle Introduction to Markov Chain Monte Carlo (M ...
-
明明已经执行Log.i,偏偏打不出日志
Android内打日志用的当然是Log.i(tag,string),调试时的日志输出可以很快的反映一些问题,方便我们跟进. 但是如果连日志都打不出来了怎么办呢,我今天就遇到了比较坑的问题.项目里别的日 ...
-
WampServer集成环境安装与配置
实习到了第三个礼拜了,原来我们小组是以开发php为主的,我们项目的服务器也是用php做的,因此我觉得很有必要学一下php的相关知识,首先当然是搭建环境了,写篇博客分享下经验. 目录: 一.软件下载 二 ...
-
用原生javascript做的一个打地鼠的小游戏
学习javascript也有一段时间了,一直以来分享的都是一些概念型的知识,今天有空做了一个打地鼠的小游戏,来跟大家分享一下,大家也可以下载来增加一些生活的乐趣,下面P出代码:首先是HTML部分代码: ...
-
14、NFC技术:使用Android Beam技术传输文本
Android Beam的基本理念 Android Beam的基本理念就是两部(只能是两部)NFC设备靠近时(一般是背靠背),通过触摸一部NFC设备的屏幕,将数据推向另外一部NFC设备.在传递数据的过 ...
-
headfirst设计模式(4)—工厂模式
开篇 天天逛博客园,就是狠不下心来写篇博客,忙是一方面,但是说忙能有多忙呢,都有时间逛博客园,写篇博客的时间都没有?(这还真不好说) 每次想到写一篇新的设计模式,我总会问自己: 1,自己理解了吗? 2 ...
-
p201 谱集是闭集 有界集
1 是如何来的? 由1 如何推出 2 2 是如何来的?谢谢 1.σ是的补集 入属于ρ 稠密是因为 T有定义的地方,λI-T都有定义,有界是因为 所以 然后 ρ是σ的补集 模比||T||大的数都 ...
-
BBU和RRU具体区别是 什么?
RRU是Remote Radio Unit 远端射频模块,BBU是Building Baseband Unit 室内基带处理单元.基带BBU集中放置在机房,RRU可安装至楼层,BBU与RRU之间采用光 ...
-
Python3编写网络爬虫08-数据存储方式一-文件存储
数据存储 用解析器解析出数据之后,就是存储数据了.保存的形式可以多种多样,最简单的形式是直接保存为文本文件,如TXT JSON CSV等.另外还可以保存到数据库中,如关系型数据库MySQL 非关系型数 ...
-
RecyclerView的单击和长按事件(转)
转自:http://www.jianshu.com/p/f2e0463e5aef 前言 上一篇文章揭开RecyclerView的神秘面纱(一):RecyclerView的基本使用中,主要讲述了Recy ...