Подтвердить что ты не робот

System.Net.WebException: операция завершена

У меня большая проблема: мне нужно отправить 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;, но это не помогло.

4b9b3361

Ответ 1

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

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

Ответ 2

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

Ответ 3

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

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

  • У вас есть максимальное количество активных подключений по умолчанию к одному и тому же хосту 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 с сервером остается открытым до тех пор, пока вы не достигнете конца этого потока (фактически закрывая его, поскольку он не доступен для поиска), вручную закройте его самостоятельно или он будет удален. Подробнее об этом здесь.

Ответ 4

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