每次一个工作实例完成工作,相应的_reqsBusy就设为false,并调用DispatchWork,那么DispatchWork就能给空闲的实例分配新任务了。
接下来是发送请求
private void RequestResource(int index)
{
int depth;
string url = "";
try
{
lock (_locker)
{
if (_urlsUnload.Count <= 0) //判断是否还有未下载的URL
{
_workingSignals.FinishWorking(index); //设置工作实例的状态为Finished
return;
}
_reqsBusy[index] = true;
_workingSignals.StartWorking(index); //设置工作状态为Working
depth = _urlsUnload.First().Value; //取出第一个未下载的URL
url = _urlsUnload.First().Key;
_urlsLoaded.Add(url, depth); //把该URL加入到已下载里
_urlsUnload.Remove(url); //把该URL从未下载中移除
}
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.Method = _method; //请求方法
req.Accept = _accept; //接受的内容
req.UserAgent = _userAgent; //用户代理
RequestState rs = new RequestState(req, url, depth, index); //回调方法的参数
var result = req.BeginGetResponse(new AsyncCallback(ReceivedResource), rs); //异步请求
ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle, //注册超时处理方法
TimeoutCallback, rs, _maxTime, true);
}
catch (WebException we)
{
MessageBox.Show("RequestResource " + we.Message + url + we.Status);
}
}
第7行为了保证多个任务并发时的同步,加上了互斥锁。_locker是一个Object类型的成员变量。
第9行判断未下载集合是否为空,如果为空就把当前工作实例状态设为Finished;如果非空则设为Working并取出一个URL开始下载。当所有工作实例都为Finished的时候,说明下载已经完成。由于每次下载完一个URL后都调用DispatchWork,所以可能激活其他的Finished工作实例重新开始工作。
第26行的请求的额外信息在异步请求的回调方法作为参数传入,之后还会提到。
第27行开始异步请求,这里需要传入一个回调方法作为响应请求时的处理,同时传入回调方法的参数。
第28行给该异步请求注册一个超时处理方法TimeoutCallback,最大等待时间是_maxTime,且只处理一次超时,并传入请求的额外信息作为回调方法的参数。
RequestState的定义是
class RequestState
{
private const int BUFFER_SIZE = 131072; //接收数据包的空间大小
private byte[] _data = new byte[BUFFER_SIZE]; //接收数据包的buffer
private StringBuilder _sb = new StringBuilder(); //存放所有接收到的字符
public HttpWebRequest Req { get; private set; } //请求
public string Url { get; private set; } //请求的URL
public int Depth { get; private set; } //此次请求的相对深度
public int Index { get; private set; } //工作实例的编号
public Stream ResStream { get; set; } //接收数据流
public StringBuilder Html
{
get
{
return _sb;
}
}
public byte[] Data
{
get
{
return _data;
}
}
public int BufferSize
{
get
{
return BUFFER_SIZE;
}
}
public RequestState(HttpWebRequest req, string url, int depth, int index)
{
Req = req;
Url = url;
Depth = depth;
Index = index;
}
}










