您的位置:首页 > 其它

有关多线程下载有关资料与总结

2009-08-23 13:15 246 查看
实例1 转自c# 多线程下载

实例2 转自用C#实现HTTP协议下的多线程文件传输

HTTP协议,HTTP亦即Hpyer Text Transfer Protocal的缩写,它是现代互联网上最重要的一种网络协议,超文本传输协议

位于TCP/IP协议的应用层,是一个面向无连接、简单、快速的C/S结构的协议。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 既接收内容的长度。

总结的代码
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using System.Threading;

namespace 下载网页进度程序
{
public class ManyTheardingLoad
{
#region 数据定义
private int _threadNum;             //线程数量
private long _fileSize;             //文件大小
private string _extName;            //文件扩展名
private string _fileUrl;            //文件地址
private string _fileName;           //文件名
private string _savePath;           //保存路径
private short _threadCompleteNum;   //线程完成数量
private bool _isComplete;           //是否完成
private volatile int _downloadSize; //当前下载大小
private Thread[] _thread;           //线程数组
private List<string> _tempFiles = new List<string>();

public string FileName
{
get
{
return _fileName;
}
set
{
_fileName = value;
}
}

public long FileSize
{
get
{
return _fileSize;
}
}

public int DownloadSize
{
get
{
return _downloadSize;
}
}

public bool IsComplete
{
get
{
return _isComplete;
}
set
{
_isComplete = value;
}
}

public int ThreadNum
{
get
{
return _threadNum;
}
set
{
_threadNum = value;
}
}

public string SavePath
{
get
{
return _savePath;
}
set
{
_savePath = value;
}
}

#endregion

public ManyTheardingLoad(int threahNum, string fileUrl, string savePath)
{
this._threadNum = threahNum;
this._thread = new Thread[threahNum];
this._fileUrl = fileUrl;
this._savePath = savePath;
}

public void Start()
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(_fileUrl);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
_extName = response.ResponseUri.ToString().Substring(response.ResponseUri.ToString().LastIndexOf('.'));//获取真实扩展名
_fileSize = response.ContentLength;
int singelNum = (int)(_fileSize / _threadNum);      //平均分配
int remainder = (int)(_fileSize % _threadNum);      //获取剩余的
request.Abort();
response.Close();
for (int i = 0; i < _threadNum; i++)
{
List<int> range = new List<int>();
range.Add(i * singelNum);
if (remainder != 0 && (_threadNum - 1) == i)    //剩余的交给最后一个线程
range.Add(i * singelNum + singelNum + remainder - 1);
else
range.Add(i * singelNum + singelNum - 1);

//实例线程带方法的参数
ThreadStart starter = delegate { Download(range[0], range[1]); };
_thread[i] = new Thread(starter);
//方法二
//_thread[i] = new Thread(new ParameterizedThreadStart(Download));// _thread[i].Start(range[0], range[1]);
_thread[i].Name =string.Format("tmpfile_{0}",(i + 1));
_thread[i].Start();
}
}

private void Download(int from, int to)
{
Stream httpFileStream = null, localFileStram = null;
try
{
string tmpFileBlock =string.Format(@"{0}/{1}_{2}.dat",_savePath, _fileName, Thread.CurrentThread.Name);
_tempFiles.Add(tmpFileBlock);
HttpWebRequest httprequest = (HttpWebRequest)WebRequest.Create(_fileUrl);
httprequest.AddRange(from, to);
HttpWebResponse httpresponse = (HttpWebResponse)httprequest.GetResponse();
httpFileStream = httpresponse.GetResponseStream();
localFileStram = new FileStream(tmpFileBlock, FileMode.Create);
byte[] by = new byte[5000];
int getByteSize = httpFileStream.Read(by, 0, (int)by.Length);           //Read方法将返回读入by变量中的总字节数
while (getByteSize > 0)
{
Thread.Sleep(20);
_downloadSize += getByteSize;
localFileStram.Write(by, 0, getByteSize);
getByteSize = httpFileStream.Read(by, 0, (int)by.Length);
}
_threadCompleteNum++;
}
catch (Exception ex)
{
throw new Exception(ex.Message.ToString());
}
finally
{
if (httpFileStream != null) httpFileStream.Dispose();
if (localFileStram != null) localFileStram.Dispose();
}
if (_threadCompleteNum == _threadNum)
{
//自加,防止线冲冲突
_threadCompleteNum++;
_isComplete = true;
Complete();
}
}

private void Complete()
{
Stream mergeFile = new FileStream(string.Format(@"{0}/{1}{2}",_savePath, _fileName, _extName), FileMode.Create);
BinaryWriter AddWriter = new BinaryWriter(mergeFile);
foreach (string file in _tempFiles)
{
using (FileStream fs = new FileStream(file, FileMode.Open))
{
BinaryReader TempReader = new BinaryReader(fs);
AddWriter.Write(TempReader.ReadBytes((int)fs.Length));
TempReader.Close();
}
File.Delete(file);
}
AddWriter.Close();
}

}
}


主线程

ManyTheardingLoad load = new ManyTheardingLoad(
int.Parse(txt_threadnum.Text), txt_url.Text, txt_filepath.Text);

load.FileName = txt_filename.Text;

DateTime sdt = DateTime.Now;

load.Start();

//progressBar1.Value = 0;
//progressBar1.Maximum = (int)load.FileSize;
while (!load.IsComplete)
{

//progressBar1.Value = load.DownloadSize;
}

DateTime edt = DateTime.Now;

TimeSpan ts = edt.Subtract(sdt);

MessageBox.Show("完成/n开始时间" + sdt.ToLongTimeString() + "   结束时间:" + edt.ToLongTimeString() +
"经过 "+ts.Seconds.ToString()+"秒");


重点还要学习多线程的处理。流文件的处理也是个很有意思的地方

这里不可避免的遇到了个问题,线程同步。如_threadCompleteNum++,因为是多个线程同时并发执行,在此句之后可能会造成有两个或两个以上线程认为_threadCompleteNum == _threadNum 条件(=5)都成立,例如第五个线程刚执行完_threadCompleteNum++,而第四个线程刚执行到条件判断,则造成两个条件都成立,而执行两次Complete()合并文件的方法。

还有例如主线程被调用多次,就是Btn多次单击生成多个主线程,解决此方法使用了Lock语句。

转自使用C# lock同时访问期间共享数据

主线程的LOCK在外部声明静态变量

private static object run = new object();

再在主线程的第一句加lock (run)

这样不会造成多个主线程同时访问生成的暂时文件资源造成冲突。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: