为什么我在不是超时时收到“操作已超时”?

Jea*_*ôté 1 c# http httpwebrequest ip-camera

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

  1. 我有一个每 500 毫秒调用一次的计时器。
  2. 计时器中的代码调用执行 http 请求的线程。

所以很有可能当定时器被调用时,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);
}
Run Code Online (Sandbox Code Playgroud)

* 编辑 *

为了回答评论,我得到的错误在 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
Run Code Online (Sandbox Code Playgroud)

Jim*_*hel 5

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;
Run Code Online (Sandbox Code Playgroud)

补充意见:

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

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

当然,这并不能解释超时,除非出于某种原因ServicePointManager或其他原因,因为有太多未完成的请求而决定终止它。您可能会查看异常堆栈跟踪以查看超时异常是在哪里引发的。

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

我认为您遇到了并发问题。如果多个线程可以同时执行此代码(您表示这是可能的),那么ListTest除非它是某种线程安全列表,否则您可能会被破坏。