多线程与断点续传

断点续传技术实现及.NET框架应用
引自
http://www.devdiv.com/thread-20925-1-1.html


本帖最后由 wt0731 于 2010-1-15 09:01 编辑


起因:公司有个项目用到了断点续传,之前开发了一套但是由于现场环境的问题导致不能用(原理是用aspnet_isapi.dll来响应PUT和POST请求),后来考虑换个模式,当中要感谢帮助过我的人(pkwsh、egmkang等)
1、断点续传的原理(来自网络)
在了解HTTP断点续传的原理之前,先来说说HTTP协议,HTTP协议是一种基于tcp的简单协议,分为请求和回复两种。
请求协议是由客户机(浏览器)向服务器(WEB SERVER)提交请求时发送报文的协议。回复协议是由服务器(web ser
ver),向客户机(浏览器)回复报文时的协议。请求和回复协议都由头和体组成。头和体之间以一行空行为分隔。
以下是一个请求报文与相应的回复报文的例子:
GET /image/index_r4_c1.jpg HTTP/1.1
Accept: */*
Referer: http://192.168.3.120:8080/
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705)
Host: 192.168.3.120:8080
Connection: Keep-Alive
HTTP/1.1 200 OK
Server: Microsoft-IIS/5.0
Date: Tue, 24 Jun 2003 05:39:40 GMT
Content-Type: image/jpeg
Accept-Ranges: bytes
Last-Modified: Thu, 23 May 2002 03:05:40 GMT
ETag: "bec48eb862c21:934"
Content-Length: 2827
….

下面我们就来说说“断点续传”。
顾名思义,断点续传就是在上一次下载时断开的位置开始继续下载。在HTTP协议中,可以在请求报文头中加入Rang
e段,来表示客户机希望从何处继续下载。
比如说从第1024字节开始下载,请求报文如下:

GET /image/index_r4_c1.jpg HTTP/1.1
Accept: */*
Referer: http://192.168.3.120:8080/
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705)
Host: 192.168.3.120:8080
Range:bytes=1024-
Connection: Keep-Alive

.NET中的相关类
明白了上面的原理,那么,我们来看看.NET FRAMEWORK中为我们提供了哪些类可以来做这些事。

完成HTTP请求
System.Net.HttpWebRequest

HttpWebRequest 类对 WebRequest 中定义的属性和方法提供支持,也对使用户能够直接与使用 HTTP 的服务器交互
的附加属性和方法提供支持。

HttpWebRequest 将发送到 Internet 资源的公共 HTTP 标头值公开为属性,由方法或系统设置。下表包含完整列表
。可以将 Headers 属性中的其他标头设置为名称/值对。但是注意,某些公共标头被视为受限制的,它们或者直接
由 API公开,或者受到系统保护,不能被更改。Range也属于被保护之列,不过,.NET为开发者提供了更方便的操作
,就是 AddRange方法,向请求添加从请求数据的开始处或结束处的特定范围的字节范围标头

完成文件访问
System.IO.FileStream

FileStream 对象支持使用Seek方法对文件进行随机访问, Seek 允许将读取/写入位置移动到文件中的任意位置。这
是通过字节偏移参考点参数完成的。字节偏移量是相对于查找参考点而言的,该参考点可以是基础文件的开始、当
前位置或结尾,分别由SeekOrigin类的三个属性表示。

2、网上的可以跑的示例
代码实现
了解了.NET提供的相关的类,那么,我们就可以方便的实现了。

代码如下:

static void Main(string[] args)
{
string StrFileName="c:\\aa.zip"; //根据实际情况设置
string StrUrl="http://www.xxxx.cn/xxxxx.zip"; //根据实际情况设置


//打开上次下载的文件或新建文件
long lStartPos =0;
System.IO.FileStream fs;
if (System.IO.File.Exists(StrFileName))
{
fs= System.IO.File.OpenWrite(StrFileName);
lStartPos=fs.Length;
fs.Seek(lStartPos,System.IO.SeekOrigin.Current); //移动文件流中的当前指

}
else
{
fs = new System.IO.FileStream(StrFileName,System.IO.FileMode.Create);
lStartPos =0;
}
//打开网络连接
try
{
System.Net.HttpWebRequest request =(System.Net.HttpWebRequest)System.Net
.HttpWebRequest.Create(StrUrl);
if ( lStartPos>0)
request.AddRange((int)lStartPos); //设置Range值
//向服务器请求,获得服务器回应数据流
System.IO.Stream ns= request.GetResponse().GetResponseStream();
byte[] nbytes = new byte[512];
int nReadSize=0;
nReadSize=ns.Read(nbytes,0,512);
while( nReadSize >0)
{
fs.Write(nbytes,0,nReadSize);
nReadSize=ns.Read(nbytes,0,512);
}
fs.Close();
ns.Close();
Console.WriteLine("下载完成");
}
catch(Exception ex)
{
fs.Close();
Console.WriteLine("下载过程中出现错误:"+ex.ToString());
}
3、服务端的配置

配置一个站点,并给Asp.Net和NetWorkService用读取并运行权限
4、完善(加上简单逻辑、多线程)
#region 作者:wt0731, 2010-01-02
/*
* 版本 :1.0
* 维护者:
* 最近维护日期:
*
*/
#endregion
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace DownloadFile
{
public partial class FormDownLoad : Form
{
private Thread threadDownload = null;
private Thread threadUpload = null;
/// <summary>
/// 下载路径
/// </summary>
private string DownloadPath = "http://192.168.100.46/HttpHandle/2.rar";//根据实际需要修改

/// <summary>
/// 本地存储路径
/// </summary>
private string localSourceFile = string.Empty;
/// <summary>
/// 暂停
/// </summary>
private bool dlThreadContinue = false;
public FormDownLoad()
{
InitializeComponent();
this.btnStop.Enabled = false;
}

private void btnDownLoad_Click(object sender, EventArgs e)
{
Cursor.Current = Cursors.WaitCursor;
this.btnDownLoad.Enabled = false;
this.dlThreadContinue = true;
this.btnStop.Enabled = true;
localSourceFile = System.Environment.GetFolderPath(Environment.SpecialFolder.Personal) + "\\" + this.txtName.Text.ToString(); //根据实际情况设置
DownloadPath = this.txtUrl.Text.ToString(); //根据实际情况设置
threadDownload = new Thread(new ThreadStart(DownloadThread));
threadDownload.Start();
}

/// <summary>
/// 下载线程的入口函数
/// </summary>
void DownloadThread()
{
DownloadFile(this.DownloadPath,this.localSourceFile);
}

/// <summary>
/// 下载文件,无压缩传输
/// </summary>
/// <param name="serverUrl">服务端处理Http请求的地址</param>param>
/// <param name="fileName">本地存储的文件名</param>
private void DownloadFile(string serverUrl, string fileName)
{
//打开上次下载的文件或新建文件
long lStartPos = 0;
System.IO.FileStream fs;
if (System.IO.File.Exists(fileName))
{
fs = System.IO.File.OpenWrite(fileName);
lStartPos = fs.Length;
fs.Seek(lStartPos, System.IO.SeekOrigin.Current); //移动文件流中的当前指针
}
else
{
fs = new System.IO.FileStream(fileName, System.IO.FileMode.Create);
lStartPos = 0;
}
//打开网络连接
try
{
System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(serverUrl);
request.KeepAlive = true;
if (lStartPos > 0)
request.AddRange((int)lStartPos); //设置Range值
System.Text.Encoding utf8 = System.Text.Encoding.Default;
//向服务器请求,获得服务器回应数据流
System.IO.Stream ns = request.GetResponse().GetResponseStream();

byte[] nbytes = new byte[1024];
int nReadSize = 0;
nReadSize = ns.Read(nbytes, 0, 1024);
while (nReadSize > 0 && dlThreadContinue)
{
fs.Write(nbytes, 0, nReadSize);
nReadSize = ns.Read(nbytes, 0, 1024);
}
//fs.Flush();
fs.Close();
ns.Close();
Cursor.Current = Cursors.Default;
MessageBox.Show("下载完成", "系统提示");
}
catch (Exception ex)
{
Cursor.Current = Cursors.Default;
fs.Close();
MessageBox.Show("下载过程中出现错误:" + ex.ToString(), "系统提示");
}
}
private void menuItem1_Click(object sender, EventArgs e)
{
Application.Exit();
}

private void btnStop_Click(object sender, EventArgs e)
{
if (this.btnStop.Text == "暂停")
{
this.dlThreadContinue = false;
Cursor.Current = Cursors.Default;
this.btnDownLoad.Enabled = true;
this.btnStop.Enabled = false;
}
}
}
}
复制代码
扩展资料:
HttpWebRequest&HttpWebResponse Headers
介绍
这里简要介绍如何使用HttpWebRequest&HttpWebResponse两个对象与HTTP服务器进行直接交互的过程.HttpWebRequest类对WebRequest中定义的属性和方法提供支持,在使用HttpWebRequest对象向HTTP服务器发起请求时请不要使用HttpWebRequest对象的构造函数,而应该使用WebRequest.Create()方法来初始化新的HttpWebRequest对象.如果统一资源标识符方案是"http://"或"https://"时,Create()则返回HttpWebResponse对象.
代码
首先,我们需要创建一个新的HttpWebRequest对象,代码如下:
HttpWebRequest myrequest = (HttpWebRequest)WebRequest.Create(new Uri("urlstring"));
注意:上文中已经提到过不要使用HttpWebRequest的构造函数来创建对象;使用WebRequest.Create()方法初始化HttpWebRequest对象时应该对其进行类型转换.
接下来可以对新初始化的对象进行简单操作,比如可以设置它的标头属性,
下表列出了由属性或方法设置或由系统设置的标头:
________________________________________

标头 设置方法
Accept 由Accept属性设置
Connection 由Connection属性和KeepAlive属性设置
Content-Length 由ContentLength属性设置
Content-Type 由ContentType属性设置
Expect 由Expect属性设置
Date 由系统设置为当前日期
Host 由系统设置为当前主机信息
If-Modified-Since 由IfModifiedSince属性设置
Range 由Range属性设置
Transfer-Encoding 由TransferEncoding属性设置
Referer 由Referer属性设置
User-Agent 由UserAgent属性设置
________________________________________
注意:HttpWebRequest自动注册.使用以"http://"或"https://"开头的URL之前,不需要调用RegisterPrefix方法来注册
源码下载:
微信营销系统(第三方微信平台)之微分销模块拓展(附件包括所有源码和数据库、说明文档) 平台框架作者:曹旭升 微分销模块作者:wt0731 在线体验:http://wxcm.eeipo.cn/ 一、微分销是什么? 无论是线下还是线上,获客和流量都是高转化的前提。因此,为了解决这个问题,我们推出了扁平式发展分销商,让更多的卖家成为卖家,大幅度降低销售成本。 微分销系统,让所有参分享和推广的人都能成为受益者,让新会员、老会员、潜客、信息安全人员成为一个共同体,形成高粘性的闭环。 微分销,是基于微信公众平台上的二级分销商城,是伴随着微信营销的火热而兴起的一种网络营销方式。 微分销(即微信分销),在大数据时代背景下企业数据营销方式,是基于微信公众平台定制研发,专门为品牌公司和商家提供微信连锁商城、微分销渠道的二级分销微信商城体系,微分销助力商家高粘度、快速将自媒体转化为自有分销商。 二、分销原理 生产厂商或品牌公司基于公司微信服务号上部署微分销商城,员工和经销商在公司的微信分销商城基础上生成专属于自己的一个分销商城(员工经销商即二级分销商),员工的朋友或者经销商的客户在员工或经销商的个人微信商城基础上再次生成个人分销商城(朋友客户即三级分销商),从而实现公司零成本泛员工业态。 分销模式:全民分销、渠道分销 四、一期实现的功能(现阶段) 4.1、PC后端 1、增加渠道管理; 2、增加返佣清单; 3、修改订单详情,添加返佣详情; 4、添加查看下级功能; 5、添加审核渠道人员入口; 6、后台提供改价功能(解决部分地区有优惠的场景) 7、解决返佣是按照特点价格(例如扣除评测中心部分) 8、微主页扩展“我的分销Url” {{#DCCenterUrl}}标签 4.2、微信端: 1、增加“我的分销”页面:实现分销相关的信息显示和入口(我的返佣、我的下级、推广海报、我的推广码、) 2、增加“我的返佣”页面; 3、增加“我的下级”页面;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值