欢迎光临
我们一直在努力

.Net/C#: 实现支持断点续传多线程下载的 Http Web 客户端工具类 (C# DIY HttpWebClient)-.NET教程,C#语言

建站超值云服务器,限时71元/月

/* .net/c#: 实现支持断点续传多线程下载的 http web 客户端工具类 (c# diy httpwebclient)

* reflector 了一下 system.net.webclient ,重载或增加了若干:

* download、upload 相关方法!

* download 相关改动较大!

* 增加了 datareceive、exceptionoccurrs 事件!

* 了解服务器端与客户端交互的 http 协议参阅:

* 使文件下载的自定义连接支持 flashget 的断点续传多线程链接下载! jsp/servlet 实现!

* http://blog.csdn.net/playyuer/archive/2004/08/02/58430.aspx

* 使文件下载的自定义连接支持 flashget 的断点续传多线程链接下载! c#/asp.net 实现!

* http://blog.csdn.net/playyuer/archive/2004/08/02/58281.aspx

*/

namespace microshaoft.utils

{

using system;

using system.io;

using system.net;

using system.text;

using system.security;

using system.threading;

using system.collections.specialized;

/// <summary>

/// 记录下载的字节位置

/// </summary>

public class downloadstate

{

private string _filename;

private string _attachmentname;

private int _position;

private string _requesturl;

private string _responseurl;

private int _length;

private byte[] _data;

public string filename

{

get

{

return _filename;

}

}

public int position

{

get

{

return _position;

}

}

public int length

{

get

{

return _length;

}

}

public string attachmentname

{

get

{

return _attachmentname;

}

}

public string requesturl

{

get

{

return _requesturl;

}

}

public string responseurl

{

get

{

return _responseurl;

}

}

public byte[] data

{

get

{

return _data;

}

}

internal downloadstate(string requesturl, string responseurl, string filename, string attachmentname, int position, int length, byte[] data)

{

this._filename = filename;

this._requesturl = requesturl;

this._responseurl = responseurl;

this._attachmentname = attachmentname;

this._position = position;

this._data = data;

this._length = length;

}

internal downloadstate(string requesturl, string responseurl, string filename, string attachmentname, int position, int length, threadcallbackhandler tch)

{

this._requesturl = requesturl;

this._responseurl = responseurl;

this._filename = filename;

this._attachmentname = attachmentname;

this._position = position;

this._length = length;

this._threadcallback = tch;

}

internal downloadstate(string requesturl, string responseurl, string filename, string attachmentname, int position, int length)

{

this._requesturl = requesturl;

this._responseurl = responseurl;

this._filename = filename;

this._attachmentname = attachmentname;

this._position = position;

this._length = length;

}

private threadcallbackhandler _threadcallback;

//

internal void startdownloadfilechunk()

{

if (this._threadcallback != null)

{

this._threadcallback(this._requesturl, this._filename, this._position, this._length);

}

}

}

//委托代理线程的所执行的方法签名一致

public delegate void threadcallbackhandler(string s, string s, int i, int i);

//异常处理动作

public enum exceptionactions

{

throw,

cancelall,

ignore,

retry

}

/// <summary>

/// 包含 exception 事件数据的类

/// </summary>

public class exceptioneventargs : system.eventargs

{

private system.exception _exception;

private exceptionactions _exceptionaction;

private downloadstate _downloadstate;

public downloadstate downloadstate

{

get

{

return _downloadstate;

}

}

public exception exception

{

get

{

return _exception;

}

}

public exceptionactions exceptionaction

{

get

{

return _exceptionaction;

}

set

{

_exceptionaction = value;

}

}

internal exceptioneventargs(system.exception e, downloadstate downloadstate)

{

this._exception = e;

this._downloadstate = downloadstate;

}

}

/// <summary>

/// 包含 download 事件数据的类

/// </summary>

public class downloadeventargs : system.eventargs

{

private downloadstate _downloadstate;

public downloadstate downloadstate

{

get

{

return _downloadstate;

}

}

public downloadeventargs(downloadstate downloadstate)

{

this._downloadstate = downloadstate;

}

}

/// <summary>

/// 支持断点续传多线程下载的类

/// </summary>

public class httpwebclient

{

private static object _synclockobject = new object();

public delegate void datareceiveeventhandler(httpwebclient sender, downloadeventargs e);

public event datareceiveeventhandler datareceive; //接收字节数据事件

public delegate void exceptioneventhandler(httpwebclient sender, exceptioneventargs e);

public event exceptioneventhandler exceptionoccurrs; //发生异常事件

private int _filelength; //下载文件的总大小

public int filelength

{

get

{

return _filelength;

}

}

/// <summary>

/// 分块下载文件

/// </summary>

/// <param name="address">url 地址</param>

/// <param name="filename">保存到本地的路径文件名</param>

/// <param name="chunkscount">块数,线程数</param>

public void downloadfile(string address, string filename, int chunkscount)

{

int p = 0; // position

int s = 0; // chunk size

string a = null;

httpwebrequest hwrq;

httpwebresponse hwrp = null;

try

{

hwrq = (httpwebrequest) webrequest.create(this.geturi(address));

hwrp = (httpwebresponse) hwrq.getresponse();

long l = hwrp.contentlength;

hwrq.credentials = this.m_credentials;

l = ((l == -1) || (l > 0x7fffffff)) ? ((long) 0x7fffffff) : l; //int32.maxvalue 该常数的值为 2,147,483,647; 即十六进制的 0x7fffffff

int l = (int) l;

this._filelength = l;

// 在本地预定空间(竟然在多线程下不用先预定空间)

// filestream sw = new filestream(filename, filemode.openorcreate, fileaccess.readwrite, fileshare.readwrite);

// sw.write(new byte[l], 0, l);

// sw.close();

// sw = null;

bool b = (hwrp.headers["accept-ranges"] != null & hwrp.headers["accept-ranges"] == "bytes");

a = hwrp.headers["content-disposition"]; //attachment

if (a != null)

{

a = a.substring(a.lastindexof("filename=") + 9);

}

else

{

a = filename;

}

int ss = s;

if (b)

{

s = l / chunkscount;

if (s < 2 * 64 * 1024) //块大小至少为 128 k 字节

{

s = 2 * 64 * 1024;

}

ss = s;

int i = 0;

while (l > s)

{

l -= s;

if (l < s)

{

s += l;

}

if (i++ > 0)

{

downloadstate x = new downloadstate(address, hwrp.responseuri.absolutepath, filename, a, p, s, new threadcallbackhandler(this.downloadfilechunk));

// 单线程下载

// x.startdownloadfilechunk();

//多线程下载

//thread t =

new thread(new threadstart(x.startdownloadfilechunk)).start();

//t.start();

}

p += s;

}

s = ss;

byte[] buffer = this.responseasbytes(address, hwrp, s, filename);

// lock (_synclockobject)

// {

// this._bytes += buffer.length;

// }

}

}

catch (exception e)

{

exceptionactions ea = exceptionactions.throw;

if (this.exceptionoccurrs != null)

{

downloadstate x = new downloadstate(address, hwrp.responseuri.absolutepath, filename, a, p, s);

exceptioneventargs eea = new exceptioneventargs(e, x);

exceptionoccurrs(this, eea);

ea = eea.exceptionaction;

}

if (ea == exceptionactions.throw)

{

if (!(e is webexception) && !(e is securityexception))

{

throw new webexception("net_webclient", e);

}

throw;

}

}

}

/// <summary>

/// 下载一个文件块,利用该方法可自行实现多线程断点续传

/// </summary>

/// <param name="address">url 地址</param>

/// <param name="filename">保存到本地的路径文件名</param>

/// <param name="length">块大小</param>

public void downloadfilechunk(string address, string filename, int fromposition, int length)

{

httpwebresponse hwrp = null;

string a = null;

try

{

//this._filename = filename;

httpwebrequest hwrq = (httpwebrequest) webrequest.create(this.geturi(address));

//hwrq.credentials = this.m_credentials;

hwrq.addrange(fromposition);

hwrp = (httpwebresponse) hwrq.getresponse();

a = hwrp.headers["content-disposition"]; //attachment

if (a != null)

{

a = a.substring(a.lastindexof("filename=") + 9);

}

else

{

a = filename;

}

byte[] buffer = this.responseasbytes(address, hwrp, length, filename);

// lock (_synclockobject)

// {

// this._bytes += buffer.length;

// }

}

catch (exception e)

{

exceptionactions ea = exceptionactions.throw;

if (this.exceptionoccurrs != null)

{

downloadstate x = new downloadstate(address, hwrp.responseuri.absolutepath, filename, a, fromposition, length);

exceptioneventargs eea = new exceptioneventargs(e, x);

exceptionoccurrs(this, eea);

ea = eea.exceptionaction;

}

if (ea == exceptionactions.throw)

{

if (!(e is webexception) && !(e is securityexception))

{

throw new webexception("net_webclient", e);

}

throw;

}

}

}

internal byte[] responseasbytes(string requesturl, webresponse response, long length, string filename)

{

string a = null; //attachmentname

int p = 0; //整个文件的位置指针

int num2 = 0;

try

{

a = response.headers["content-disposition"]; //attachment

if (a != null)

{

a = a.substring(a.lastindexof("filename=") + 9);

}

long num1 = length; //response.contentlength;

bool flag1 = false;

if (num1 == -1)

{

flag1 = true;

num1 = 0x10000; //64k

}

byte[] buffer1 = new byte[(int) num1];

int p = 0; //本块的位置指针

string s = response.headers["content-range"];

if (s != null)

{

s = s.replace("bytes ", "");

s = s.substring(0, s.indexof("-"));

p = convert.toint32(s);

}

int num3 = 0;

stream s = response.getresponsestream();

do

{

num2 = s.read(buffer1, num3, ((int) num1) – num3);

num3 += num2;

if (flag1 && (num3 == num1))

{

num1 += 0x10000;

byte[] buffer2 = new byte[(int) num1];

buffer.blockcopy(buffer1, 0, buffer2, 0, num3);

buffer1 = buffer2;

}

// lock (_synclockobject)

// {

// this._bytes += num2;

// }

if (num2 > 0)

{

if (this.datareceive != null)

{

byte[] buffer = new byte[num2];

buffer.blockcopy(buffer1, p, buffer, 0, buffer.length);

downloadstate dls = new downloadstate(requesturl, response.responseuri.absolutepath, filename, a, p, num2, buffer);

downloadeventargs dlea = new downloadeventargs(dls);

//触发事件

this.ondatareceive(dlea);

//system.threading.thread.sleep(100);

}

p += num2; //本块的位置指针

p += num2; //整个文件的位置指针

}

else

{

break;

}

}

while (num2 != 0);

s.close();

s = null;

if (flag1)

{

byte[] buffer3 = new byte[num3];

buffer.blockcopy(buffer1, 0, buffer3, 0, num3);

buffer1 = buffer3;

}

return buffer1;

}

catch (exception e)

{

exceptionactions ea = exceptionactions.throw;

if (this.exceptionoccurrs != null)

{

downloadstate x = new downloadstate(requesturl, response.responseuri.absolutepath, filename, a, p, num2);

exceptioneventargs eea = new exceptioneventargs(e, x);

exceptionoccurrs(this, eea);

ea = eea.exceptionaction;

}

if (ea == exceptionactions.throw)

{

if (!(e is webexception) && !(e is securityexception))

{

throw new webexception("net_webclient", e);

}

throw;

}

return null;

}

}

private void ondatareceive(downloadeventargs e)

{

//触发数据到达事件

datareceive(this, e);

}

public byte[] uploadfile(string address, string filename)

{

return this.uploadfile(address, "post", filename, "file");

}

public string uploadfileex(string address, string method, string filename, string fieldname)

{

return encoding.ascii.getstring(uploadfile(address, method, filename, fieldname));

}

public byte[] uploadfile(string address, string method, string filename, string fieldname)

{

byte[] buffer4;

filestream stream1 = null;

try

{

filename = path.getfullpath(filename);

string text1 = "———————" + datetime.now.ticks.tostring("x");

string text2 = "application/octet-stream";

stream1 = new filestream(filename, filemode.open, fileaccess.read);

webrequest request1 = webrequest.create(this.geturi(address));

request1.credentials = this.m_credentials;

request1.contenttype = "multipart/form-data; boundary=" + text1;

request1.method = method;

string[] textarray1 = new string[7] {"–", text1, "\r\ncontent-disposition: form-data; name=\"" + fieldname + "\"; filename=\"", path.getfilename(filename), "\"\r\ncontent-type: ", text2, "\r\n\r\n"};

string text3 = string.concat(textarray1);

byte[] buffer1 = encoding.utf8.getbytes(text3);

byte[] buffer2 = encoding.ascii.getbytes("\r\n–" + text1 + "\r\n");

long num1 = 0x7fffffffffffffff;

try

{

num1 = stream1.length;

request1.contentlength = (num1 + buffer1.length) + buffer2.length;

}

catch

{

}

byte[] buffer3 = new byte[math.min(0x2000, (int) num1)];

using (stream stream2 = request1.getrequeststream())

{

int num2;

stream2.write(buffer1, 0, buffer1.length);

do

{

num2 = stream1.read(buffer3, 0, buffer3.length);

if (num2 != 0)

{

stream2.write(buffer3, 0, num2);

}

}

while (num2 != 0);

stream2.write(buffer2, 0, buffer2.length);

}

stream1.close();

stream1 = null;

webresponse response1 = request1.getresponse();

buffer4 = this.responseasbytes(response1);

}

catch (exception exception1)

{

if (stream1 != null)

{

stream1.close();

stream1 = null;

}

if (!(exception1 is webexception) && !(exception1 is securityexception))

{

//throw new webexception(sr.getstring("net_webclient"), exception1);

throw new webexception("net_webclient", exception1);

}

throw;

}

return buffer4;

}

private byte[] responseasbytes(webresponse response)

{

int num2;

long num1 = response.contentlength;

bool flag1 = false;

if (num1 == -1)

{

flag1 = true;

num1 = 0x10000;

}

byte[] buffer1 = new byte[(int) num1];

stream stream1 = response.getresponsestream();

int num3 = 0;

do

{

num2 = stream1.read(buffer1, num3, ((int) num1) – num3);

num3 += num2;

if (flag1 && (num3 == num1))

{

num1 += 0x10000;

byte[] buffer2 = new byte[(int) num1];

buffer.blockcopy(buffer1, 0, buffer2, 0, num3);

buffer1 = buffer2;

}

}

while (num2 != 0);

stream1.close();

if (flag1)

{

byte[] buffer3 = new byte[num3];

buffer.blockcopy(buffer1, 0, buffer3, 0, num3);

buffer1 = buffer3;

}

return buffer1;

}

private namevaluecollection m_requestparameters;

private uri m_baseaddress;

private icredentials m_credentials = credentialcache.defaultcredentials;

public icredentials credentials

{

get

{

return this.m_credentials;

}

set

{

this.m_credentials = value;

}

}

public namevaluecollection querystring

{

get

{

if (this.m_requestparameters == null)

{

this.m_requestparameters = new namevaluecollection();

}

return this.m_requestparameters;

}

set

{

this.m_requestparameters = value;

}

}

public string baseaddress

{

get

{

if (this.m_baseaddress != null)

{

return this.m_baseaddress.tostring();

}

return string.empty;

}

set

{

if ((value == null) || (value.length == 0))

{

this.m_baseaddress = null;

}

else

{

try

{

this.m_baseaddress = new uri(value);

}

catch (exception exception1)

{

throw new argumentexception("value", exception1);

}

}

}

}

private uri geturi(string path)

{

uri uri1;

try

{

if (this.m_baseaddress != null)

{

uri1 = new uri(this.m_baseaddress, path);

}

else

{

uri1 = new uri(path);

}

if (this.m_requestparameters == null)

{

return uri1;

}

stringbuilder builder1 = new stringbuilder();

string text1 = string.empty;

for (int num1 = 0; num1 < this.m_requestparameters.count; num1++)

{

builder1.append(text1 + this.m_requestparameters.allkeys[num1] + "=" + this.m_requestparameters[num1]);

text1 = "&";

}

uribuilder builder2 = new uribuilder(uri1);

builder2.query = builder1.tostring();

uri1 = builder2.uri;

}

catch (uriformatexception)

{

uri1 = new uri(path.getfullpath(path));

}

return uri1;

}

}

}

/// <summary>

/// 测试类

/// </summary>

class apptest

{

static void main()

{

apptest a = new apptest();

microshaoft.utils.httpwebclient x = new microshaoft.utils.httpwebclient();

//订阅 datareceive 事件

x.datareceive += new microshaoft.utils.httpwebclient.datareceiveeventhandler(a.x_datareceive);

//订阅 exceptionoccurrs 事件

x.exceptionoccurrs += new microshaoft.utils.httpwebclient.exceptioneventhandler(a.x_exceptionoccurrs);

string f = "http://localhost/download/phpmyadmin-2.6.1-pl2.zip";

a._f = f;

f = "http://localhost/download/jdk-1_5_0_01-windows-i586-p.aa.exe";

//f = "http://localhost/download/resharper1.5.exe";

//f = "http://localhost/mywebapplications/webapplication7/webform1.aspx";

//f = "http://localhost:1080/test/download.jsp";

//f = "http://localhost/download/webcast20050125_ppt.zip";

//f = "http://www.morequick.com/greenbrowsergb.zip";

//f = "http://localhost/download/test_local.rar";

string f = f.substring(f.lastindexof("/") + 1);

//(new system.threading.thread(new system.threading.threadstart(new threadprocessstate(f, @"e:\temp\" + f, 10, x).startthreadprocess))).start();

x.downloadfile(f, @"e:\temp\temp\" + f, 10);

// x.downloadfilechunk(f, @"e:\temp\" + f,15,34556);

system.console.readline();

// upload 测试

// string uploadfile = "e:\\test_local.rar";

// string str = x.uploadfileex("http://localhost/phpmyadmin/uploadaction.php", "post", uploadfile, "file1");

// system.console.writeline(str);

// system.console.readline();

}

string bs = ""; //用于记录上次的位数

bool b = false;

private int i = 0;

private static object _synclockobject = new object();

string _f;

string _f;

private void x_datareceive(microshaoft.utils.httpwebclient sender, microshaoft.utils.downloadeventargs e)

{

if (!this.b)

{

lock (_synclockobject)

{

if (!this.b)

{

system.console.write(system.datetime.now.tostring() + " 已接收数据: ");

//system.console.write( system.datetime.now.tostring() + " 已接收数据: ");

this.b = true;

}

}

}

string f = e.downloadstate.filename;

if (e.downloadstate.attachmentname != null)

f = system.io.path.getdirectoryname(f) + @"\" + e.downloadstate.attachmentname;

this._f = f;

using (system.io.filestream sw = new system.io.filestream(f, system.io.filemode.openorcreate, system.io.fileaccess.readwrite, system.io.fileshare.readwrite))

{

sw.position = e.downloadstate.position;

sw.write(e.downloadstate.data, 0, e.downloadstate.data.length);

sw.close();

}

string s = system.datetime.now.tostring();

lock (_synclockobject)

{

this.i += e.downloadstate.data.length;

system.console.write(bs + "\b\b\b\b\b\b\b\b\b\b" + i + " / " + sender.filelength + " 字节数据 " + s);

//system.console.write(bs + i + " 字节数据 " + s);

this.bs = new string(\b, digits(i) + 3 + digits(sender.filelength) + s.length);

}

}

int digits(int n) //数字所占位数

{

n = system.math.abs(n);

n = n / 10;

int i = 1;

while (n > 0)

{

n = n / 10;

i++;

}

return i;

}

private void x_exceptionoccurrs(microshaoft.utils.httpwebclient sender, microshaoft.utils.exceptioneventargs e)

{

system.console.writeline(e.exception.message);

//发生异常重新下载相当于断点续传,你可以自己自行选择处理方式或自行处理

microshaoft.utils.httpwebclient x = new microshaoft.utils.httpwebclient();

x.downloadfilechunk(this._f, this._f, e.downloadstate.position, e.downloadstate.length);

e.exceptionaction = microshaoft.utils.exceptionactions.ignore;

}

}

/*

* 用于 upload 测试的 action php:

http://localhost/phpmyadmin/uploadaction.php:

<!doctype html public "-//w3c//dtd html 4.0 transitional//en">

<html>

<head>

<title> new document </title>

</head>

<body>

<?php

print_r($_request);

$uploaddir = ;

$uploadfile = $uploaddir . $_files[file1][name];

print "<pre>";

if (move_uploaded_file($_files[file1][tmp_name], $uploadfile))

{

print "file is valid, and was successfully uploaded. ";

}

else

{

print "possible file upload attack! heres some debugging info:\n";

print_r($_files);

}

print "</pre>";

?>

</body>

</html>

*/

赞(0)
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com 特别注意:本站所有转载文章言论不代表本站观点! 本站所提供的图片等素材,版权归原作者所有,如需使用,请与原作者联系。未经允许不得转载:IDC资讯中心 » .Net/C#: 实现支持断点续传多线程下载的 Http Web 客户端工具类 (C# DIY HttpWebClient)-.NET教程,C#语言
分享到: 更多 (0)

相关推荐

  • 暂无文章