簡體   English   中英

我正在獲取WebException:“操作已超時”立即在HttpWebRequest.GetResponse()上

[英]I am getting WebException: “The operation has timed out” immediately on HttpWebRequest.GetResponse()

我在多線程環境中大量抓取網頁內容。 我需要一個可靠的下載程序組件,可以容忍臨時服務器故障,連接丟失等。下面是我的代碼的樣子。

現在,我一遍又一遍地處於一種奇怪的境地:這一切都完美無缺。 10個線程同時拉數據大約10分鍾。 在那之后,我在調用請求對象的GetResponse方法后立即開始獲取帶有超時的WebException。 休息一下(讓線程入睡)並沒有幫助。 它只有在我停止應用程序並啟動它直到接下來的10分鍾通過並且問題再次出現時才有用。

我已經嘗試過但沒有任何幫助:

  • 通過“using”語句顯式關閉/處置響應對象
  • 打電話請求。到處都可以幫助他們
  • 在ServicePointManager / ServicePoint和WebRequest級別操作超時(延長/縮短超時間隔)
  • 操縱KeepAlive屬性
  • 調用CloseConnectionGroup
  • 操縱同時運行的線程的數量

什么都沒有幫助! 所以它似乎是一個錯誤或至少記錄很差的行為。 我在谷歌和Stackoverflow上看到了很多關於這個的問題,但是沒有完全回答。 基本上人們會從上面的列表中提出一些建議。 我嘗試了所有這些。

    public TResource DownloadResource(Uri uri)
    {
        for (var resourceReadingAttempt = 0; resourceReadingAttempt <= MaxTries; resourceReadingAttempt++)
        {
            var request = (HttpWebRequest)WebRequest.Create(uri);
            HttpWebResponse response = null;
            for (var downloadAttempt = 0; downloadAttempt <= MaxTries; downloadAttempt++)
            {
                if (downloadAttempt > 0)
                {
                    var sleepFor = TimeSpan.FromSeconds(4 << downloadAttempt) + TimeSpan.FromMilliseconds(new Random(DateTime.Now.Millisecond).Next(1000));
                    Trace.WriteLine("Retry #" + downloadAttempt + " in " + sleepFor + ".");
                    Thread.Sleep(sleepFor);
                }
                Trace.WriteLine("Trying to get a resource by URL: " + uri);

                var watch = Stopwatch.StartNew();
                try
                {
                    response = (HttpWebResponse)request.GetResponse();
                    break;
                }
                catch (WebException exception)
                {
                    request.Abort();
                    Trace.WriteLine("Failed to get a resource by the URL: " + uri + " after " + watch.Elapsed + ". " + exception.Message);
                    if (exception.Status == WebExceptionStatus.Timeout)
                    {
                        //Trace.WriteLine("Closing " + request.ServicePoint.CurrentConnections + " current connections.");
                        //request.ServicePoint.CloseConnectionGroup(request.ConnectionGroupName);
                        //request.Abort();
                        continue;
                    }
                    else
                    {
                        using (var failure = exception.Response as HttpWebResponse)
                        {

                            Int32 code;
                            try { code = failure != null ? (Int32)failure.StatusCode : 500; }
                            catch { code = 500; }

                            if (code >= 500 && code < 600)
                            {
                                if (failure != null) failure.Close();
                                continue;
                            }
                            else
                            {
                                Trace.TraceError(exception.ToString());
                                throw;
                            }
                        }
                    }
                }
            }

            if (response == null) throw new ApplicationException("Unable to get a resource from URL \"" + uri + "\".");
            try
            {
                // response disposal is required to eliminate problems with timeouts
                // more about the problem: http://stackoverflow.com/questions/5827030/httpwebrequest-times-out-on-second-call
                // http://social.msdn.microsoft.com/Forums/en/netfxnetcom/thread/a2014f3d-122b-4cd6-a886-d619d7e3140e

                TResource resource;
                using (var stream = response.GetResponseStream())
                {
                    try
                    {
                        resource = this.reader.ReadFromStream(stream);
                    }
                    catch (IOException exception)
                    {
                        Trace.TraceError("Unable to read the resource stream: " + exception.ToString());
                        continue;
                    }
                }
                return resource;
            }
            finally
            {
                // recycle as much as you can
                if (response != null)
                {
                    response.Close();
                    (response as IDisposable).Dispose();
                    response = null;
                }
                if (request != null)
                {
                    //Trace.WriteLine("closing connection group: " + request.ConnectionGroupName);
                    //request.ServicePoint.CloseConnectionGroup(request.ConnectionGroupName);
                    request.Abort();
                    request = null;
                }
            }
        }
        throw new ApplicationException("Resource was not able to be acquired after several attempts.");
    }

我有同樣的問題我在互聯網上搜索了很多,我有一個解決方案,一次修復線程數。你必須一次控制線程數,我一次開始使用2-3線程。 也使用此ServicePointManager.DefaultConnectionLimit = 200; 這真的會對你有所幫助。

暫無
暫無

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

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