【问题标题】:Multithread HttpWebRequest hangs randomly on responseStream多线程 HttpWebRequest 在 responseStream 上随机挂起
【发布时间】:2014-07-24 04:59:06
【问题描述】:

我正在编写一个多线程网络爬虫,它每秒使用数百个线程执行大量并发 httpwebrequests,应用程序运行良好,但有时(随机)其中一个网络请求挂在 getResponseStream() 上,完全忽略了超时(当我同时执行数百个请求时会发生这种情况)使得爬取过程永远不会结束,奇怪的是,对于 fiddler,这永远不会发生并且应用程序永远不会挂起,真的很难调试,因为它是随机发生的。

我试过设置

保活 = 假

ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;

但我仍然有奇怪的行为,有什么想法吗?

谢谢

HttpWebRequest 代码:

  public static string RequestHttp(string url, string referer, ref CookieContainer cookieContainer_0, IWebProxy proxy)
    {
        string str = string.Empty;
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
        request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
        request.UserAgent = randomuseragent();
        request.ContentType = "application/x-www-form-urlencoded";
        request.Accept = "*/*";
        request.CookieContainer = cookieContainer_0;
        request.Proxy = proxy;
        request.Timeout = 15000;
        request.Referer = referer;
        //request.ServicePoint.MaxIdleTime = 15000;
        using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
        {
            using (Stream responseStream = response.GetResponseStream())
            {
                List<byte> list = new List<byte>();
                byte[] buffer = new byte[0x400];
                int count = responseStream.Read(buffer, 0, buffer.Length);
                while (count != 0)
                {
                    list.AddRange(buffer.ToList<byte>().GetRange(0, count));
                    if (list.Count >= 0x100000)
                    {
                        break;
                    }
                    count = 0;
                    try
                    {
           HERE IT HANGS SOMETIMES --->             count = responseStream.Read(buffer, 0, buffer.Length);
                        continue;
                    }
                    catch
                    {
                        continue;
                    }
                }
                //responseStream.Close();
                int num2 = 0x200 * 0x400;
                if (list.Count >= num2)
                {
                    list.RemoveRange((num2 * 3) / 10, list.Count - num2);
                }
                byte[] bytes = list.ToArray();
                str = Encoding.Default.GetString(bytes);
                Encoding encoding = Encoding.Default;
                if (str.ToLower().IndexOf("charset=") > 0)
                {
                    encoding = GetEncoding(str);
                }
                else
                {
                    try
                    {
                        encoding = Encoding.GetEncoding(response.CharacterSet);
                    }
                    catch
                    {
                    }
                }
                str = encoding.GetString(bytes);
               // response.Close();
            }
        }
        return str.Trim();
    }

【问题讨论】:

    标签: c# multithreading httpwebrequest fiddler freeze


    【解决方案1】:

    Timeout 属性“获取或设置 GetResponse 和 GetRequestStream 方法的超时值(以毫秒为单位)。”默认值为 100,000 毫秒(100 秒)。

    ReadWriteTimeout 属性,“在写入或读取流时获取或设置超时(以毫秒为单位)。”默认值为 300,000 毫秒(5 分钟)。

    您正在设置Timeout,但将ReadWriteTimeout 保留为默认值,因此您的读取最多可能需要五分钟才能超时。您可能希望将ReadWriteTimeout 设置为较低的值。您还可以考虑限制下载的数据大小。使用我的爬虫时,我有时会偶然发现一个无休止的流,最终会导致内存不足异常。

    我在抓取时注意到的另一件事是有时关闭响应流会挂起。我发现如果我想在读取整个流之前退出,我必须调用 request.Abort 才能可靠地终止请求。

    【讨论】:

    • 是的,我已经尝试了 ReadWriteTimeout,我只是删除了它,因为我正在使用 Fiddler 进行测试,如果打开 Fiddler,问题永远不会发生并且没有请求挂起(不使用 ReadWriteTimeout),我'我现在只是在和提琴手一起调查,为什么如果我继续打开它会“修复”我的应用程序。
    【解决方案2】:

    您提供的代码中没有任何明显内容。

    你为什么评论 response.Close() 出来?

    文档提示如果未明确关闭连接可能会耗尽。处理的响应可能会关闭连接,但我认为仅释放所有资源并不是最佳的。关闭响应也会关闭流,以便覆盖。

    没有超时的系统挂起可能只是一个网络问题,使响应对象成为死鸭,或者问题是由于大量线程导致内存碎片。

    查看任何可能产生模式的事物可能有助于找到源头:

    1. 通常有多少线程正在运行(您能否将请求集捆绑在更少的线程中)
    2. 线程停止时网络性能如何
    3. 发生时是否有特定的计数或范围
    4. 发生时最后处理了什么数据(是否有任何特定的控制字符或数据序列会扰乱流)

    想问更多问题但声望不够所以只能回复。

    祝你好运!

    【讨论】:

    • 当前 1 个线程 = 1 个请求,我认为它不依赖于网络性能,因为它发生在 win7 和我运行 win 2008 的服务器上,它完全随机地发生在随机 url 上,但这一切如果我一直打开 fiddler 就修复了,它永远不会挂起,这很奇怪,我不是 fiddler 调试方面的专家,这是我第一次编写多线程应用程序。
    【解决方案3】:

    下面是一些做类似事情的代码,它也用于访问多个网站,每个调用都在不同的任务中。不同之处在于我只读取一次流然后解析结果。这可能是一种绕过流阅读器随机锁定的方法,或者至少使它更容易调试。

           try
           {
               _webResponse = (HttpWebResponse)_request.GetResponse();
               if(_request.HaveResponse)
               {
                   if (_webResponse.StatusCode == HttpStatusCode.OK)
                   {
                       var _stream = _webResponse.GetResponseStream();
                       using (var _streamReader = new StreamReader(_stream))
                       {
                           string str = _streamReader.ReadToEnd();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-08
      相关资源
      最近更新 更多