分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.youkuaiyun.com/jiangjunshow
关于HttpWebRequest.AddRange()方法的参数
2009-02-06 21:14:18| 分类: DotNET(c#) 阅读563 评论3 字号:大中小 订阅
先讲一个故事吧!
我:“Server,请告诉我那个文件有多大?”(当你和Server对话时必须很有礼貌)
Server:“好吧,孩子,那是一个相当大的文件,6个G。你知道的,我很聪明,那就是为什么我是Server你是Client,你可以请求这个文件的一部分。告诉我你想要文件的哪一部分,随你从什么地方开始到什么地方结束,我会把那部分文件给你发过去。”
我:“你看,我已经下载了那个文件的前5个G,让我看看...,嗯...6-5...,怎么计算才最简单呢?嗯...我想我正好需要最后一个G。”
我的程序:webRequest.Headers.Add("range", 5 Gb)
WebRequest:“Oh,不是这样的,你不可以这样,你要用AddRange方法,我会帮助你做好的。”
我:“好吧,我再来...”
我的程序:webRequest.AddRange(from)
编译器:“Oh,你个小笨蛋!你想这个Int64的变量试试吗?我会看着你...”
我:“什么?!WebRequest?难道你不把一个Int64变量当做一个合法的值吗?”
WebRequest:“事实上...我恐怕是这样的。你不得不一次下载完这个大文件...嘿!但是你可以等到.net 4.5,你可能用一些更好用的方法,比如说P2P、增强的设计模式、DTC或其他更多的...”
我:“OK!听起来不错!但是...现在,我还是想用一些现成的办法!难道我还要自已新实现一个吗?”
WebRequest:“好的,但我还是恐怕是的,但你可以首先在一些论坛问一下,我非常确信你不是第一个遇到这个问题的人。我记得我爷爷,WinINet,或多或少的也有这个问题。这是个遗传...或者被设计,就象我们经常说的。”
我:“...有点象是旧事重提了...”
原文请看:http://objectmix.com/dotnet/252325-httpwebrequest-inconsistency-8-a.html
解决办法请继续看。
WebRequest.ContentLength属性是Int64型的,但是AddRange方法只接受Int32型的参数,所在我们在分段下载大于2个G的文件时,在大于(Int32.MaxValue)的地方时,我们就无法实现分段下载了,意味着大于2GB之后的文件必须用一个线程一次下完,否则文件大于2GB的部分我们无法下载。
我也反编过HttpWebRequest,其中有一个私有方法,AddRange(string rangeSpecifier,string from,string to)。但我忘了可以用反射来得到这个方法并调用之,看了上篇帖子后才恍然大悟,其中提到了两种方法,一种是利用反射,一种是利用动态写入一个新方法来实现。
两段代码如下:
利用反射:
object[] args = new object[3];
req = (HttpWebRequest)HttpWebRequest.Create(txtURL.Text);
args[0] = "bytes";
args[1]=start.ToString();
args[2]=end.ToString();
MethodInfo[] mi = t.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic);
for (MethodI = 0; MethodI < mi.Length; MethodI++)
{
if (mi[MethodI].Name == "AddRange") break;
}
mi[MethodI].Invoke(req, args);
动态方法:
public delegate void _AddRange(HttpWebRequest httpWebRequest, string rangeSpecifier, string from, string to);
static public _AddRange delegateAddRange;
static AddRangeCodeGenerator()
{
Type stringType = typeof(string);
DynamicMethod dynamicMethod = new DynamicMethod("AddRange", typeof(void), new Type[] {
typeof (HttpWebRequest), stringType, stringType, stringType },
typeof(AddRangeCodeGenerator), true);
ILGenerator ilGenerator = dynamicMethod.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldarg_1);
ilGenerator.Emit(OpCodes.Ldarg_2);
ilGenerator.Emit(OpCodes.Ldarg_3);
ilGenerator.Emit(OpCodes.Call, typeof(System.Net.HttpWebRequest).GetMethod("AddRange",
BindingFlags.Instance | BindingFlags.NonPublic));
ilGenerator.Emit(OpCodes.Pop);
ilGenerator.Emit(OpCodes.Ret);
delegateAddRange = dynamicMethod.CreateDelegate(typeof(_AddRange)) as _AddRange;
}
AddRange的实现方法如下:
private bool AddRange(string rangeSpecifier, string from, string to)
{
string str = this._HttpRequestHeaders["Range"];
if ((str == null) || (str.Length == 0))
{
str = rangeSpecifier + "=";
}
else
{
if (string.Compare(str.Substring(0, str.IndexOf('=')), rangeSpecifier, 5) != 0)
{
return false;
}
str = string.Empty;
}
str = str + from.ToString();
if (to != null)
{
str = str + "-" + to;
}
this._HttpRequestHeaders.SetAddVerified("Range", str);
return true;
}
这个方法,实现设置HTTP 的Range 标头。具体规范参考HTTP1.1协议规范Header Field Definitions
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
rangeSpecifier:指的是规范中的bytes-unit,一般是bytes
比如:从第1024字节开始下载,则请求报文如下
Range:bytes=1024-
一般用在断点续传和多线程下载。一些多线程下载的软件你可以看到分块,每个分块从不同的位置下载
分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.youkuaiyun.com/jiangjunshow