当没有超时时,为什么我收到“操作已超时”?

时间:2011-10-26 18:22:28

标签: c# http httpwebrequest ip-camera

我正在做一个向IP摄像头发出HTTP请求的应用程序。每次我发出HTTP请求时,都会收到一张在屏幕上绘制的图片。所有这些过程都是这样完成的:

  1. 我有一个每500毫秒调用一次的计时器。
  2. 计时器中的代码调用执行http请求的线程。
  3. 因此很有可能在调用计时器时,http请求没有完全完成,就可以了。

    问题是,有时,由于未知原因,我收到异常“操作已超时”。所以我做了一个操作日志。我记录http请求之前的时间和之后的时间。它总是在300-400毫秒左右。我也在异常中做了一个日志,我的惊喜是记录的时间是24或76毫秒。我的超时设置为5000毫秒,因此它永远不会超时!

    在我的所有测试中,我从未发现超过800毫秒的记录时间,并且在设置的超时时间内。

    还有其他原因可以解释错误“操作已超时”吗?我也尝试ServicePointManager.DefaultConnectionLimit = 200;,但它没有改变任何东西。

    非常感谢!

    这是有线程的代码。 ListTest是记录器,然后每行打印到一个文件。

    StructTakePicture structTP = (StructTakePicture)structTakePicture;
    ServicePointManager.DefaultConnectionLimit = 200; 
    string strFileName = structTP.FolderGUID + "input" + GetNumeroPhoto(structTP.Cam.ID, structTP.NumPhoto) + ".jpg";
    DateTime dateDebut = DateTime.Now;
    try
    {
        ListTest.Add(strFileName + " --- BEGIN : " + dateDebut.ToString()); 
    
        WebRequest WebRequestObject = HttpWebRequest.Create(String.Format("http://{0}/mjpg/snapshot.cgi?camera={1}", structTP.Cam.TotalIP, structTP.Cam.View));
        WebRequestObject.Timeout = 5000;
        WebRequestObject.Credentials = new NetworkCredential("admin", "admin");
        HttpWebResponse ResponseObject = (HttpWebResponse)WebRequestObject.GetResponse();
    
        string strTypeRetour = ResponseObject.ContentType;
    
        if (strTypeRetour == "image/jpeg")
        {
            MemoryStream memoryStream = new MemoryStream(0x10000);
    
            using (Stream responseStream = WebRequestObject.GetResponse().GetResponseStream())
            {
                byte[] buffer = new byte[0x1000];
                int bytes;
                while ((bytes = responseStream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    memoryStream.Write(buffer, 0, bytes);
                }
    
                ResponseObject.Close();
            }
    
            byte[] response = memoryStream.ToArray();
            Image img = byteArrayToImage(response);
    
    
            img.Save(strFileName);
            structTP.StopEverything = false;
            DateTime dateFin = DateTime.Now;
            TimeSpan span = dateFin.Subtract(dateDebut);
            ListTest.Add(strFileName + " --- TOTALTIME:" + span.Milliseconds.ToString());
            ListTest.Add(strFileName + " --- END : " + dateFin.ToString());
        }
    }
    catch (System.Net.WebException err)
    {
        structTP.StopEverything = true;
        DateTime dateFin = DateTime.Now;
        TimeSpan span = dateFin.Subtract(dateDebut);
        ListTest.Add(strFileName + " === ERROR :" + span.Milliseconds + " | " + err.Message);
    }
    

    *编辑*

    要回答这些评论,我得到的错误是在System.Net.WebException中,而err.Message是“操作已经超时”。

    *编辑2 *

    这是我用代码做的日志的一部分。如您所见,接收超时的响应时间非常短。

    C:\Users\jfcote\AppData\Local\Temp\d1785720-afc6-4822-b02d-fdf6d2f2c0d1\input1_00013.jpg --- BEGIN : 2011-10-27 08:16:46
        C:\Users\jfcote\AppData\Local\Temp\d1785720-afc6-4822-b02d-fdf6d2f2c0d1\input1_00010.jpg --- TOTALTIME:353
        C:\Users\jfcote\AppData\Local\Temp\d1785720-afc6-4822-b02d-fdf6d2f2c0d1\input1_00010.jpg --- END : 2011-10-27 08:16:47
        C:\Users\jfcote\AppData\Local\Temp\d1785720-afc6-4822-b02d-fdf6d2f2c0d1\input2_00006.jpg --- TOTALTIME:610
        C:\Users\jfcote\AppData\Local\Temp\d1785720-afc6-4822-b02d-fdf6d2f2c0d1\input2_00006.jpg --- END : 2011-10-27 08:16:47
        C:\Users\jfcote\AppData\Local\Temp\d1785720-afc6-4822-b02d-fdf6d2f2c0d1\input2_00008.jpg --- BEGIN : 2011-10-27 08:16:47
        C:\Users\jfcote\AppData\Local\Temp\d1785720-afc6-4822-b02d-fdf6d2f2c0d1\input1_00014.jpg --- BEGIN : 2011-10-27 08:16:47
        C:\Users\jfcote\AppData\Local\Temp\d1785720-afc6-4822-b02d-fdf6d2f2c0d1\input2_00009.jpg --- BEGIN : 2011-10-27 08:16:47
        C:\Users\jfcote\AppData\Local\Temp\d1785720-afc6-4822-b02d-fdf6d2f2c0d1\input2_00005.jpg --- TOTALTIME:996
        C:\Users\jfcote\AppData\Local\Temp\d1785720-afc6-4822-b02d-fdf6d2f2c0d1\input2_00005.jpg --- END : 2011-10-27 08:16:48
        C:\Users\jfcote\AppData\Local\Temp\d1785720-afc6-4822-b02d-fdf6d2f2c0d1\input2_00004.jpg --- TOTALTIME:800
        C:\Users\jfcote\AppData\Local\Temp\d1785720-afc6-4822-b02d-fdf6d2f2c0d1\input2_00004.jpg --- END : 2011-10-27 08:16:48
        C:\Users\jfcote\AppData\Local\Temp\d1785720-afc6-4822-b02d-fdf6d2f2c0d1\input1_00007.jpg === ERROR :22 | The operation has timed out
        C:\Users\jfcote\AppData\Local\Temp\d1785720-afc6-4822-b02d-fdf6d2f2c0d1\input1_00015.jpg --- BEGIN : 2011-10-27 08:16:48
        C:\Users\jfcote\AppData\Local\Temp\d1785720-afc6-4822-b02d-fdf6d2f2c0d1\input1_00014.jpg --- TOTALTIME:391
        C:\Users\jfcote\AppData\Local\Temp\d1785720-afc6-4822-b02d-fdf6d2f2c0d1\input1_00014.jpg --- END : 2011-10-27 08:16:49
        C:\Users\jfcote\AppData\Local\Temp\d1785720-afc6-4822-b02d-fdf6d2f2c0d1\input1_00009.jpg === ERROR :23 | The operation has timed out
        C:\Users\jfcote\AppData\Local\Temp\d1785720-afc6-4822-b02d-fdf6d2f2c0d1\input2_00008.jpg --- TOTALTIME:526
        C:\Users\jfcote\AppData\Local\Temp\d1785720-afc6-4822-b02d-fdf6d2f2c0d1\input2_00008.jpg --- END : 2011-10-27 08:16:50
        C:\Users\jfcote\AppData\Local\Temp\d1785720-afc6-4822-b02d-fdf6d2f2c0d1\input1_00012.jpg --- TOTALTIME:461
        C:\Users\jfcote\AppData\Local\Temp\d1785720-afc6-4822-b02d-fdf6d2f2c0d1\input1_00012.jpg --- END : 2011-10-27 08:16:50
        C:\Users\jfcote\AppData\Local\Temp\d1785720-afc6-4822-b02d-fdf6d2f2c0d1\input1_00015.jpg --- TOTALTIME:780
        C:\Users\jfcote\AppData\Local\Temp\d1785720-afc6-4822-b02d-fdf6d2f2c0d1\input1_00015.jpg --- END : 2011-10-27 08:16:50
        C:\Users\jfcote\AppData\Local\Temp\d1785720-afc6-4822-b02d-fdf6d2f2c0d1\input1_00011.jpg --- TOTALTIME:49
        C:\Users\jfcote\AppData\Local\Temp\d1785720-afc6-4822-b02d-fdf6d2f2c0d1\input1_00011.jpg --- END : 2011-10-27 08:16:50
        C:\Users\jfcote\AppData\Local\Temp\d1785720-afc6-4822-b02d-fdf6d2f2c0d1\input2_00009.jpg --- TOTALTIME:133
        C:\Users\jfcote\AppData\Local\Temp\d1785720-afc6-4822-b02d-fdf6d2f2c0d1\input2_00009.jpg --- END : 2011-10-27 08:16:50
        C:\Users\jfcote\AppData\Local\Temp\d1785720-afc6-4822-b02d-fdf6d2f2c0d1\input2_00007.jpg --- TOTALTIME:140
        C:\Users\jfcote\AppData\Local\Temp\d1785720-afc6-4822-b02d-fdf6d2f2c0d1\input2_00007.jpg --- END : 2011-10-27 08:16:51
        C:\Users\jfcote\AppData\Local\Temp\d1785720-afc6-4822-b02d-fdf6d2f2c0d1\input1_00013.jpg === ERROR :28 | The operation has timed out
        C:\Users\jfcote\AppData\Local\Temp\d1785720-afc6-4822-b02d-fdf6d2f2c0d1\input2_00010.jpg --- BEGIN : 2011-10-27 08:16:56
    

1 个答案:

答案 0 :(得分:3)

您设置的Timeout值是GetResponse响应的时间。 HttpWebRequest还具有在读取或写入时使用的ReadWriteTimeout值。您没有设置ReadWriteTimeout,因此GetResponse可能会在超时内返回,但读取超时。

我建议你尝试以下修改:

HttpWebRequest WebRequestObject = (HttpWebRequest)HttpWebRequest.Create(String.Format("http://{0}/mjpg/snapshot.cgi?camera={1}", structTP.Cam.TotalIP, structTP.Cam.View));
WebRequestObject.Timeout = 5000;
WebRequestObject.ReadWriteTimeout = 5000;

补充意见:

您的日志不完整,例如,文件input1_0007存在错误,但没有BEGIN行。你的ListTest是一个线程安全的集合吗?如果没有,两个线程同时更新它可能会破坏列表。

另外,您说您的代码每500毫秒发出一次请求。但是,您的日志会在一秒钟内显示三个请求。

当然,这并不能解释超时,除非由于某些原因,ServicePointManager或其他因为太多未完成的请求而决定将其删除。您可以查看异常堆栈跟踪以查看抛出超时异常的位置。

此外,您可能会考虑更改您的代码,以便在第一个代码完成之前,它永远不会向相机发出另一个请求。因此,不是每500毫秒触发一次定时器,而是启动一次定时器,延迟时间为500毫秒。定时器回调获取图片,然后重新初始化定时器500毫秒。这样,对图片的请求永远不会超过一个,并且您可以避免奇怪的并发问题。就目前而言,图片可能无序显示。

我认为你有并发问题。如果多个线程可以同时执行此代码(您表明可以执行此代码),则ListTest可能会被破坏,除非它是某种线程安全列表。