Уничтожение объекта HttpWebRequest с помощью Thread.Abort - PullRequest
6 голосов
/ 21 сентября 2010

Все, я пытаюсь отменить два одновременных HttpWebRequests, используя метод, аналогичный приведенному ниже коду (показан в псевдо-иш 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 ().

Как я могу прервать оба эти запроса таким образом, чтобы веб-сервер знал, что соединение было прервано? и / или, Есть ли лучший способ сделать это?

UPDATE

Как и предполагалось, хорошей альтернативой будет использование BeginGetResponse. Однако у меня нет доступа к объекту HttpWebRequest - он абстрагируется в классе MyHandler. Я изменил вопрос, чтобы показать это.

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

Ответы [ 3 ]

5 голосов
/ 21 сентября 2010

Используйте 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

Если вам нужно убить процесс, я бы поспорил, запустив его в новом домене приложений и отбросив домен, когда вы хотите убить запрос; вместо прерывания потока внутри вашего основного процесса.

3 голосов
/ 21 сентября 2010

ThreadAbortException крайне неспецифичен. HttpWebRequest уже поддерживает способ отмены запроса предсказуемым способом с помощью метода Abort (). Я рекомендую вам использовать его вместо этого.

Обратите внимание, что вы все равно получите исключение WebException в потоке, предназначенное для сообщения о том, что запрос был прерван извне. Будьте готовы поймать это.

2 голосов
/ 01 декабря 2011

Это может быть из-за пула соединений .NET. Каждый экземпляр WebRequest имеет ServicePoint, который описывает цель, с которой вы хотите связаться (адрес сервера, порт, протокол, ...). Эти ServicePoints будут использоваться повторно, поэтому, если вы создадите 2 веб-запроса с одинаковым адресом сервера, портом и протоколом, они будут использовать один и тот же экземпляр 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) с одинаковым именем группы соединений будут прерваны. Если у вас несколько одновременных потоков, вы можете назначить им уникальные имена групп соединений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...