Почему я получаю сообщение "Время ожидания истекло", когда оно не истекло?
Я делаю приложение, которое делает HTTP-запрос к IP-камере. Каждый раз, когда я делаю HTTP-запрос, я получаю изображение, которое рисует на экране. Весь этот процесс делается так:
- У меня есть таймер, который вызывается каждые 500 мс.
- Код в таймере вызывает поток, который выполняет 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);
}
* РЕДАКТИРОВАТЬ *
Чтобы ответить на комментарии, я получаю сообщение об ошибке в 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 ответ
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
, но нет начала строки для этого. Твой ListTest
потокобезопасная коллекция? Если нет, то два потока, обновляющие его одновременно, могут очень хорошо испортить список.
Также вы сказали, что ваш код делает запрос каждые 500 мс. Но ваш журнал показывает три запроса в течение одной секунды.
Конечно, это не объясняет тайм-аут, если по какой-то причине ServicePointManager
или что-то еще решило убить его из-за слишком большого числа невыполненных запросов. Вы можете посмотреть на трассировку стека исключений, чтобы увидеть, где было сгенерировано исключение тайм-аута.
Кроме того, вы можете подумать об изменении своего кода, чтобы он никогда не делал еще один запрос к камере, пока не будет сделан первый. Поэтому вместо таймера, который срабатывает каждые 500 мс, вы запускаете однократный таймер с задержкой в 500 мс. Обратный вызов таймера получает изображение, а затем повторно инициализирует таймер еще на 500 мс. Таким образом, никогда не будет больше одного невыполненного запроса на изображение, и вы избежите странных проблем с параллелизмом. В нынешнем виде изображения могут отображаться не по порядку.
Я думаю, что у вас проблемы с параллелизмом. Если несколько потоков могут выполнять этот код одновременно (вы указали, что это возможно), то ваш ListTest
может быть поврежден, если это не потокобезопасный список какого-либо рода.