分享
 
 
 

多线程断点续传研究之二

王朝other·作者佚名  2007-08-24
窄屏简体版  字體: |||超大  

上篇文章写完,由于整体思路是正确的,但是没有真正形成多线程下载,所以对本身的代码进行关键点的检查,尤其在一些操作web请求的地方,看看是否有什么问题,最后发现显示的关闭HttpWebResponse对象,能稍微有所改进。

原文参看:

http://blog.csdn.net/Knight94/archive/2006/08/04/1018305.aspx

那么修改后的类,大致代码如下:

//--------------------------- Download File class ---------------------------------------

//---------------------------------------------------------------------------------------

//---File: clsNewDownloadFile

//---Description: The multi-download file class file using HttpWebRequest class

//---Author: Knight

//---Date: Aug.4, 2006

//---------------------------------------------------------------------------------------

//---------------------------{Download File class}---------------------------------------

namespace DownloadFile

{

using System;

using System.IO;

using System.Net;

using System.Text;

using System.Security;

using System.Threading;

using System.Collections.Specialized;

using System.Diagnostics;

using System.Data;

/// <summary>

/// Download file info

/// </summary>

public class DownloadFileInfo

{

private string _RequestURL;

private string _ResponseURL;

private string _FileName;

private int _TotalSize;

private int _BlockLeftSize;

public string RequestURL

{

get{ return _RequestURL; }

}

public string ResponseURL

{

get{ return _ResponseURL; }

}

public string FileName

{

get{ return _FileName; }

}

public int TotalSize

{

get{ return _TotalSize;}

set{ _TotalSize = value;}

}

public int BlockLeftSize

{

get{ return _BlockLeftSize;}

set{ _BlockLeftSize = value;}

}

public DownloadFileInfo(

string RequestURL,

string ResponseURL,

string FileName,

int TotalSize,

int BlockLeftSize )

{

this._RequestURL = RequestURL;

this._ResponseURL = ResponseURL;

this._FileName = FileName;

this._TotalSize = TotalSize;

this._BlockLeftSize = BlockLeftSize;

}

public DownloadFileInfo(

string RequestURL,

string ResponseURL,

string FileName ):

this( RequestURL, ResponseURL, FileName, 0, 0 )

{

}

}

/// <summary>

/// Download event arguments

/// </summary>

public class DownLoadEventArgs : System.EventArgs

{

private DownloadFileInfo _DownloadFileInfo;

private int _Position;

private int _ReadCount;

private int _ThreadNO;

public DownloadFileInfo DownFileInfo

{

get{ return _DownloadFileInfo; }

}

public int StartPosition

{

get{ return _Position; }

}

public int ReadCount

{

get{ return _ReadCount; }

}

public int ThreadNO

{

get{ return _ThreadNO; }

}

public DownLoadEventArgs(

DownloadFileInfo DownFileInfo,

int nStartPostion,

int nReadCount,

int nThreadNO )

{

this._DownloadFileInfo = DownFileInfo;

this._Position = nStartPostion;

this._ReadCount = nReadCount;

this._ThreadNO = nThreadNO;

}

}

public delegate void DataReceivedEventHandler( DownLoadEventArgs e );

public delegate void ThreadFinishedHandler();

/// <summary>

/// class for sub-download threads

/// </summary>

public class SubDownloadThread

{

private readonly DownloadFileInfo _FileInfo;

private int _ThreadNO;

private int _Position;

private int _BlockSizeLeft;

public event DataReceivedEventHandler DataReceived;

private ThreadFinishedHandler _Finished;

private bool _IsStopped;

private Thread thdDownload;

public SubDownloadThread(

DownloadFileInfo DownFileInfo,

int ThreadNO,

int Position,

int BlockSizeLeft,

ThreadFinishedHandler Finished )

{

this._FileInfo = DownFileInfo;

this._ThreadNO = ThreadNO;

this._Position = Position;

this._BlockSizeLeft = BlockSizeLeft;

this._Finished = Finished;

}

/// <summary>

/// Start to create thread to download file

/// </summary>

public void StartDownload()

{

thdDownload = new Thread( new ThreadStart( this.Download ) );

thdDownload.Start();

}

/// <summary>

/// Stop current download-thread

/// </summary>

public void Stop()

{

_IsStopped = true;

if( thdDownload.ThreadState == System.Threading.ThreadState.Running )

thdDownload.Join( 10 );

Debug.WriteLine( string.Format( "Thread NO:{0} is stopped!" ,_ThreadNO ) );

}

/// <summary>

/// Function for sub-thread

/// </summary>

private void Download()

{

HttpWebResponse hwrp = null;

try

{

Debug.WriteLine( string.Format( "Thread NO:{0} begins to download!" ,_ThreadNO ) );

// Creat request by url

HttpWebRequest hwrq = (HttpWebRequest) WebRequest.Create(

new Uri( this._FileInfo.RequestURL ));

// Go to download position

hwrq.AddRange( _Position );

// Get response from request

hwrp = (HttpWebResponse) hwrq.GetResponse();

}

catch (Exception e)

{

Debug.WriteLine( e.Message );

return;

}

// download and write data from

Debug.WriteLine( string.Format( "Thread NO:{0} call function named DownloadData!" ,

_ThreadNO ) );

DownloadData( hwrp );

hwrp.Close();//Close response here

}

/// <summary>

/// Download data through web request

/// </summary>

/// <param name="Response"></param>

private void DownloadData( WebResponse Response )

{

const int BUFFER_SIZE = 0x10000;//64k buffer size

byte[] bBuffer = new byte[ BUFFER_SIZE ];

Stream sReader = Response.GetResponseStream();

if( sReader == null ) return;

int nReadCount = 0;

while( !_IsStopped && this._BlockSizeLeft > 0 )

{

Debug.WriteLine( string.Format( "Thread NO:{0} reads data!" ,

_ThreadNO ) );

// Set read size

nReadCount = ( BUFFER_SIZE > this._BlockSizeLeft )

? this._BlockSizeLeft:BUFFER_SIZE ;//Get current read count

// Read data

int nRealReadCount = sReader.Read( bBuffer, 0, nReadCount );

if( nRealReadCount <= 0 )

break;

Debug.WriteLine( string.Format( "Thread NO:{0} writes data!" ,

_ThreadNO ) );

// Write data

using( FileStream sw = new FileStream(

this._FileInfo.FileName,

System.IO.FileMode.OpenOrCreate,

System.IO.FileAccess.ReadWrite, System.IO.FileShare.ReadWrite))

{

sw.Position = this._Position;

sw.Write( bBuffer, 0, nRealReadCount );

Debug.WriteLine( string.Format( "Thread NO:{0} writes {1} data!" ,

_ThreadNO, nRealReadCount ) );

sw.Flush();

sw.Close();

}

Debug.WriteLine( string.Format( "Thread NO:{0} send callback info!" ,

_ThreadNO ) );

// Call back

DataReceived( new DownLoadEventArgs( this._FileInfo,

this._Position,

nRealReadCount,

this._ThreadNO ) );

// Set position and block left

this._Position += nRealReadCount;

this._BlockSizeLeft -= nRealReadCount;

}

if( _IsStopped ) return;

Debug.WriteLine( string.Format( "Thread NO:{0} sends finish-info!" ,

_ThreadNO ) );

_Finished();

}

}

/// <summary>

/// Class for download thread

/// </summary>

public class DownloadThread

{

private DownloadFileInfo _FileInfo;

private SubDownloadThread[] subThreads;

private int nThreadFinishedCount;

private DataRow drFileInfo;

private DataTable dtThreadInfo;

public DataReceivedEventHandler DataReceived;

public event ThreadFinishedHandler Finished;

/// Class's Constructor

public DownloadThread(

string RequestURL,

string ResponseURL,

string FileName,

DataRow NewFileInfo,

int SubThreadNum )

{

// Create download file info

_FileInfo = new DownloadFileInfo( RequestURL, ResponseURL, FileName );

// Create request to get file info

bool blnMultiDownload = GetFileDownInfo();

// Create file info datarow

drFileInfo = NewFileInfo;

InitDataRow();

// Create subthreads and set these info in threadinfo table

if( SubThreadNum <= 0 ) SubThreadNum = 5;//Defualt value

//Not support to be multi-thread download or less than 64k

if( !blnMultiDownload || _FileInfo.TotalSize <= 0x10000 ) SubThreadNum = 1;

subThreads = new SubDownloadThread[SubThreadNum];

nThreadFinishedCount = 0;

CreateThreadTable( SubThreadNum );

}

public DownloadThread( DataRow DownloadFileInfo, DataTable ThreadInfos )

{

// Create download file info

drFileInfo = DownloadFileInfo;

_FileInfo = new DownloadFileInfo(

drFileInfo["RequestURL"].ToString(),

drFileInfo["ResponseURL"].ToString(),

drFileInfo["FileName"].ToString(),

Convert.ToInt32( drFileInfo["TotalSize"].ToString() ),

Convert.ToInt32( drFileInfo["BlockLeftSize"].ToString() ) );

// Create sub thread class objects

dtThreadInfo = ThreadInfos;

subThreads = new SubDownloadThread[ dtThreadInfo.Rows.Count ];

nThreadFinishedCount = 0;

}

/// {Class's Constructor}

/// <summary>

/// Start to download

/// </summary>

public void Start()

{

StartSubThreads();

}

/// <summary>

/// Create table to save thread info

/// </summary>

/// <param name="SubThreadNum"></param>

private void CreateThreadTable( int SubThreadNum )

{

int nThunkSize = _FileInfo.TotalSize / SubThreadNum;

dtThreadInfo = new DataTable("DownloadFileInfo");

dtThreadInfo.Columns.Add( "ThreadNO", typeof(int) );

dtThreadInfo.Columns.Add( "Position", typeof(int) );

dtThreadInfo.Columns.Add( "BlockLeftSize", typeof(int) );

DataRow drNew;

int i = 0;

for( ; i < SubThreadNum-1; i++ )

{

drNew = dtThreadInfo.NewRow();

drNew["ThreadNO"] = i;

drNew["Position"] = i * nThunkSize;

drNew["BlockLeftSize"] = nThunkSize;

dtThreadInfo.Rows.Add( drNew );

}

drNew = dtThreadInfo.NewRow();

drNew["ThreadNO"] = i;

drNew["Position"] = i * nThunkSize;

drNew["BlockLeftSize"] = _FileInfo.TotalSize - i * nThunkSize;

dtThreadInfo.Rows.Add( drNew );

dtThreadInfo.AcceptChanges();

}

/// <summary>

/// Start sub-threads to download file

/// </summary>

private void StartSubThreads()

{

foreach( DataRow dr in dtThreadInfo.Rows )

{

int ThreadNO = Convert.ToInt32( dr["ThreadNO"].ToString() );

if( Convert.ToInt32( dr["BlockLeftSize"].ToString() ) > 0 )

{

subThreads[ ThreadNO ] = new SubDownloadThread(

_FileInfo,

ThreadNO,

Convert.ToInt32( dr["Position"].ToString() ),

Convert.ToInt32( dr["BlockLeftSize"].ToString() ),

new ThreadFinishedHandler( this.DownloadFinished ) );

subThreads[ ThreadNO ].DataReceived += this.DataReceived;

subThreads[ ThreadNO ].StartDownload();

}

else

DownloadFinished();

}

}

/// <summary>

/// Save download file info

/// </summary>

private void InitDataRow()

{

drFileInfo.BeginEdit();

drFileInfo["RequestURL"] = _FileInfo.RequestURL;

drFileInfo["ResponseURL"] = _FileInfo.ResponseURL;

drFileInfo["FileName"] = _FileInfo.FileName;

drFileInfo["TotalSize"] = _FileInfo.TotalSize;

drFileInfo["BlockLeftSize"] = _FileInfo.BlockLeftSize;

drFileInfo["CreatedTime"] = DateTime.Now.ToString( "yyyyMMddHHmmss" );

drFileInfo.EndEdit();

drFileInfo.AcceptChanges();

}

/// <summary>

/// Check url to get download file info

/// </summary>

/// <returns></returns>

private bool GetFileDownInfo()

{

HttpWebRequest hwrq;

HttpWebResponse hwrp = null;

try

{

//Create request

hwrq = (HttpWebRequest) WebRequest.Create( _FileInfo.RequestURL );

hwrp = (HttpWebResponse) hwrq.GetResponse();

//Get file size info

long L = hwrp.ContentLength;

L = ((L == -1) || (L > 0x7fffffff)) ? ((long) 0x7fffffff) : L;

_FileInfo.TotalSize = (int)L;

_FileInfo.BlockLeftSize = _FileInfo.TotalSize;

//Check whether this url is supported to be multi-threads download

bool blnMulti = ( hwrp.Headers["Accept-Ranges"] != null

&& hwrp.Headers["Accept-Ranges"] == "bytes");

hwrp.Close();//Close response here

return blnMulti;

}

catch (Exception e)

{

throw e;

}

}

/// <summary>

/// Update download thread info

/// </summary>

/// <param name="ThreadNO"></param>

/// <param name="Position"></param>

/// <param name="DownloadSize"></param>

public void UpdateDownloadInfo( int ThreadNO, int Position, int DownloadSize )

{

if( ThreadNO >= dtThreadInfo.Rows.Count ) return;

DataRow drThreadNO = dtThreadInfo.Rows[ThreadNO];

drThreadNO["Position"] = Position + DownloadSize;

drThreadNO["BlockLeftSize"] = Convert.ToInt32( drThreadNO["BlockLeftSize"].ToString() )

- DownloadSize;

drThreadNO.AcceptChanges();

drFileInfo["BlockLeftSize"] = Convert.ToInt32( drFileInfo["BlockLeftSize"].ToString() )

- DownloadSize;

}

/// <summary>

/// Stop download threads

/// </summary>

public void Stop()

{

for( int i = 0; i < subThreads.Length; i++ )

subThreads[i].Stop();

}

/// <summary>

/// Thread download finished

/// </summary>

private void DownloadFinished()

{

// Some download thread finished

nThreadFinishedCount++;

if( nThreadFinishedCount == subThreads.Length )

{

// All download threads finished

drFileInfo.Delete();

//drFileInfo.AcceptChanges();

Finished();

}

}

public DataTable ThreadInfo

{

get{ return dtThreadInfo; }

}

}

}

不过对于这个类来说,我也只实现了两个线程同时下载,当初始化为3个以上线程的时候,就有等待线程出现,这一点和我用FlashGet看到现象一样,那么估计要支持多个线程,服务器需要做些设置,不过这些还需要进一步的验证。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有