所有,我试图使用类似于下面的代码的方法取消两个并发的HttpWebRequests(以伪ish C#显示)。
Main方法创建两个创建HttpWebRequests的线程。如果用户希望,他们可以通过单击按钮然后调用Abort方法来中止请求。
private Thread first;
private Thread second;
private string uri = "http://somewhere";
public void Main()
{
first = new Thread(GetFirst);
first.Start();
second = new Thread(GetSecond);
second.Start();
// Some block on threads... like the Countdown class
countdown.Wait();
}
public void Abort()
{
try
{
first.Abort();
}
catch { // do nothing }
try
{
second.Abort();
}
catch { // do nothing }
}
private void GetFirst(object state)
{
MyHandler h = new MyHandler(uri);
h.RunRequest();
}
private void GetSecond(object state)
{
MyHandler h = new MyHandler(uri);
h.RunRequest();
}
第一个线程被SocketException中断:
A blocking operation was interrupted by a call to WSACancelBlockingCall
第二个帖子在GetResponse()上挂起。
如何以Web服务器知道连接已中止的方式中止这两个请求?,和/或有更好的方法吗?
更新
正如所建议的,一个很好的选择是使用BeginGetResponse。但是,我无权访问HttpWebRequest对象 - 它在MyHandler
类中被抽象化。我修改了这个问题来证明这一点。
public class MyHandler
{
public void RunRequest(string uri)
{
HttpWebRequest req = HttpWebRequest.Create(uri);
HttpWebResponse res = req.GetResponse();
}
}
答案 0 :(得分:5)
使用BeginGetResponse
发起呼叫,然后使用课程上的Abort
方法将其取消。
http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest_methods.aspx
我相信Abort
不适用于同步GetResponse
:
http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.abort.aspx
如果你必须坚持同步版本,要杀死这种情况,你所能做的只是中止线程。要放弃等待,您可以指定超时:
http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.timeout.aspx
如果你需要杀死进程,我会争辩在新的AppDomain中启动它并在你想杀死请求时删除AppDomain;而不是在主进程中中止一个线程。
答案 1 :(得分:3)
ThreadAbortException是非高度非特定的。 HttpWebRequest已经支持一种使用Abort()方法以可预测的方式取消请求的方法。我建议你改用它。
请注意,您仍会在该线程上获得WebException,旨在告诉您该请求已在外部中止。准备抓住它。
答案 2 :(得分:2)
这可能是因为.NET的连接池。 每个WebRequest实例都有一个ServicePoint,用于描述您要与之通信的目标(服务器地址,端口,协议......)。这些ServicePoints将被重用,因此如果您使用相同的服务器地址,端口和协议创建2个WebRequests,它们将共享相同的ServicePoint实例。
当您调用WebRequest.GetResponse()时,它使用ServicePoint提供的连接池来创建连接。如果您随后使用Thread.Abort()终止该线程,它将不会返回与ServicePoint的连接池的连接,因此ServicePoint认为此连接仍在使用中。 如果达到ServicePoint的连接限制(默认值:2),它将不会创建任何新连接,而是等待返回其中一个打开的连接。
您可以像这样增加连接限制:
HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(url);
httpRequest.ServicePoint.ConnectionLimit = 10;
或者您可以使用默认连接限制,因此每个新ServicePoint都将使用此限制:
System.Net.ServicePointManager.DefaultConnectionLimit = 10;
您还可以使用ServicePoint.CurrentConnections来获取打开的连接数。
您可以使用以下方法中止您的主题:
private Thread thread;
private Uri uri;
void StartThread()
{
thread = new Thread(new ThreadStart(() =>
{
WebRequest request = WebRequest.Create(uri);
request.ConnectionGroupName = "SomeConnectionGroup";
var response = request.GetResponse();
//...
}));
thread.Start();
}
void AbortThread()
{
thread.Abort();
ServicePointManager.FindServicePoint(uri).CloseConnectionGroup("SomeConnectionGroup");
}
请记住,将终止与具有相同连接组名称的同一服务器(或ServicePoint)的所有连接。如果您有多个并发线程,则可能需要为它们分配唯一的连接组名称。