使用Thread.Abort杀死HttpWebRequest对象

所有,我试图使用类似于下面的代码的方法取消两个并发的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服务器知道连接已中止的方式中止这两个请求? ,和/或, 有更好的方法吗?

UPDATE

正如所建议的,一个很好的选择是使用BeginGetResponse。 但是,我无法访问HttpWebRequest对象 – 它在MyHandler类中被抽象化。 我已经修改了这个问题来certificate这一点。

 public class MyHandler { public void RunRequest(string uri) { HttpWebRequest req = HttpWebRequest.Create(uri); HttpWebResponse res = req.GetResponse(); } } 

使用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; 而不是中止主进程内的线程。

ThreadAbortException是高度非特定的。 HttpWebRequest已经支持一种使用Abort()方法以可预测的方式取消请求的方法。 我建议你改用它。

请注意,您仍将在该线程上获得WebException,旨在告诉您该请求已在外部中止。 准备抓住它。

这可能是因为.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)的所有连接。 如果您有多个并发线程,则可能需要为它们分配唯一的连接组名称。