簡體   English   中英

使用Thread.Abort殺死HttpWebRequest對象

[英]Killing HttpWebRequest object using Thread.Abort

所有,我試圖使用類似於下面的代碼的方法取消兩個並發的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類中被抽象化。 我已經修改了這個問題來證明這一點。

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)的所有連接。 如果您有多個並發線程,則可能需要為它們分配唯一的連接組名稱。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM