System.Net.WebException: срок действия операции истек - PullRequest
26 голосов
/ 01 августа 2009

У меня большая проблема: мне нужно отправить 200 объектов одновременно и избежать таймаутов.

while (true)
{

    NameValueCollection data = new NameValueCollection();
    data.Add("mode", nat);

    using (var client = new WebClient())
    {
        byte[] response = client.UploadValues(serverA, data);
        responseData = Encoding.ASCII.GetString(response);

        string[] split = Javab.Split(new[] { '!' },  StringSplitOptions.RemoveEmptyEntries);
        string command = split[0];
        string server = split[1];
        string requestCountStr = split[2];

        switch (command)
        {
            case "check":
                int requestCount = Convert.ToInt32(requestCountStr);

                for (int i = 0; i < requestCount; i++)
                {
                    Uri myUri = new Uri(server);
                    WebRequest request = WebRequest.Create(myUri);
                    request.Timeout = 200000;
                    WebResponse myWebResponse = request.GetResponse();
                }
                break;
        }
    }    
}

Это приводит к ошибке:

Unhandled Exception: System.Net.WebException: The operation has timed out  
at System.Net.HttpWebRequest.GetResponse()  
at vir_fu.Program.Main(String[] args)

Цикл requestCount отлично работает вне моего базового кода, но когда я добавляю его в свой проект, я получаю эту ошибку. Я попытался установить request.Timeout = 200;, но это не помогло.

Ответы [ 5 ]

33 голосов
/ 01 августа 2009

Закрыть / удалить ваш объект WebResponse.

32 голосов
/ 01 августа 2009

Это означает, что это говорит. Операция заняла слишком много времени.

Кстати, посмотрите на WebRequest.Timeout , и вы увидите, что вы установили время ожидания на 1/5 секунды .

26 голосов
/ 01 августа 2009

Я не уверен насчет вашего первого примера кода, где вы используете WebClient.UploadValues, на самом деле этого недостаточно, не могли бы вы вставить больше окружающего кода? Что касается вашего кода WebRequest, здесь есть две вещи:

  1. Вы запрашиваете только заголовки ответа **, вы никогда не читаете тело ответа, открывая и читая (до конца) ResponseStream. Из-за этого клиент WebRequest услужливо оставляет соединение открытым, ожидая, что вы запросите тело в любой момент. Пока вы не прочитаете тело ответа до завершения (которое автоматически закроет вам поток), очистите и закроете поток (или экземпляр WebRequest) или подождите, пока GC выполнит свою задачу, ваше соединение останется открытым.

  2. У вас по умолчанию максимальное количество активных подключений к одному хосту 2. Это означает, что вы используете первые два подключения, а затем никогда не избавляетесь от них, так что ваш клиент не получает возможность завершить следующий запрос до того, как он достигнет своего тайм-аута (например, в миллисекундах, поэтому вы установили его на 0,2 секунды - по умолчанию все должно быть в порядке).

Если вы не хотите, чтобы тело ответа (или вы только что загрузили или отправили что-то и не ожидали ответа), просто закройте поток или клиент, который закроет поток для вас.

Самый простой способ исправить это - убедиться, что вы используете блоки на одноразовых предметах:

for (int i = 0; i < ops1; i++)
{
    Uri myUri = new Uri(site);
    WebRequest myWebRequest = WebRequest.Create(myUri);
    //myWebRequest.Timeout = 200;
    using (WebResponse myWebResponse = myWebRequest.GetResponse())
    {
        // Do what you want with myWebResponse.Headers.
    } // Your response will be disposed of here
}

Другое решение - разрешить 200 одновременных подключений к одному хосту. Однако, если вы не планируете многопоточность этой операции, чтобы вам потребовалось несколько одновременных подключений, это вам не очень поможет:

 ServicePointManager.DefaultConnectionLimit = 200;

Когда вы получаете тайм-ауты в коде, лучше всего попытаться воссоздать этот тайм-аут за пределами вашего кода. Если вы не можете, проблема, вероятно, кроется в вашем коде. Для этого я обычно использую cURL или просто веб-браузер, если это простой запрос GET.

** На самом деле, вы фактически запрашиваете первую порцию данных из ответа, которая содержит заголовки HTTP, а также начало тела. Вот почему можно прочитать информацию заголовка HTTP (например, Content-Encoding, Set-Cookie и т. Д.) Перед чтением из выходного потока. Когда вы читаете поток, дальнейшие данные извлекаются с сервера. Соединение WebRequest с сервером остается открытым до тех пор, пока вы не достигнете конца этого потока (фактически закрывая его, поскольку он не доступен для поиска), не закрывайте его вручную или он удаляется. Подробнее об этом здесь .

0 голосов
/ 28 марта 2018

проблема прокси может вызвать это. IIS webconfig поместил это в

<defaultProxy useDefaultCredentials="true" enabled="true">
          <proxy usesystemdefault="True" />
        </defaultProxy>
0 голосов
/ 01 августа 2009

Я помню, у меня была такая же проблема некоторое время назад при использовании WCF из-за количества данных, которые я передавал. Я помню, что везде менял таймауты, но проблема сохранялась. В конце концов я открыл соединение как потоковый запрос, мне нужно было изменить клиентскую и серверную части, но это работало именно так. Поскольку это было потоковое соединение, сервер продолжал читать, пока поток не закончился.

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