#c# #http #httpwebrequest #ip-camera
#c# #http #httpwebrequest #ip-камера
Вопрос:
Я создаю приложение, которое выполняет 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, а ошибка.Сообщение «Время ожидания операции истекло».
* РЕДАКТИРОВАТЬ 2 *
Вот часть журнала, который я сделал с кодом. Как вы можете видеть, тайм-аут получен с очень небольшим временем отклика.
C:UsersjfcoteAppDataLocalTempd1785720-afc6-4822-b02d-fdf6d2f2c0d1input1_00013.jpg --- BEGIN : 2011-10-27 08:16:46
C:UsersjfcoteAppDataLocalTempd1785720-afc6-4822-b02d-fdf6d2f2c0d1input1_00010.jpg --- TOTALTIME:353
C:UsersjfcoteAppDataLocalTempd1785720-afc6-4822-b02d-fdf6d2f2c0d1input1_00010.jpg --- END : 2011-10-27 08:16:47
C:UsersjfcoteAppDataLocalTempd1785720-afc6-4822-b02d-fdf6d2f2c0d1input2_00006.jpg --- TOTALTIME:610
C:UsersjfcoteAppDataLocalTempd1785720-afc6-4822-b02d-fdf6d2f2c0d1input2_00006.jpg --- END : 2011-10-27 08:16:47
C:UsersjfcoteAppDataLocalTempd1785720-afc6-4822-b02d-fdf6d2f2c0d1input2_00008.jpg --- BEGIN : 2011-10-27 08:16:47
C:UsersjfcoteAppDataLocalTempd1785720-afc6-4822-b02d-fdf6d2f2c0d1input1_00014.jpg --- BEGIN : 2011-10-27 08:16:47
C:UsersjfcoteAppDataLocalTempd1785720-afc6-4822-b02d-fdf6d2f2c0d1input2_00009.jpg --- BEGIN : 2011-10-27 08:16:47
C:UsersjfcoteAppDataLocalTempd1785720-afc6-4822-b02d-fdf6d2f2c0d1input2_00005.jpg --- TOTALTIME:996
C:UsersjfcoteAppDataLocalTempd1785720-afc6-4822-b02d-fdf6d2f2c0d1input2_00005.jpg --- END : 2011-10-27 08:16:48
C:UsersjfcoteAppDataLocalTempd1785720-afc6-4822-b02d-fdf6d2f2c0d1input2_00004.jpg --- TOTALTIME:800
C:UsersjfcoteAppDataLocalTempd1785720-afc6-4822-b02d-fdf6d2f2c0d1input2_00004.jpg --- END : 2011-10-27 08:16:48
C:UsersjfcoteAppDataLocalTempd1785720-afc6-4822-b02d-fdf6d2f2c0d1input1_00007.jpg === ERROR :22 | The operation has timed out
C:UsersjfcoteAppDataLocalTempd1785720-afc6-4822-b02d-fdf6d2f2c0d1input1_00015.jpg --- BEGIN : 2011-10-27 08:16:48
C:UsersjfcoteAppDataLocalTempd1785720-afc6-4822-b02d-fdf6d2f2c0d1input1_00014.jpg --- TOTALTIME:391
C:UsersjfcoteAppDataLocalTempd1785720-afc6-4822-b02d-fdf6d2f2c0d1input1_00014.jpg --- END : 2011-10-27 08:16:49
C:UsersjfcoteAppDataLocalTempd1785720-afc6-4822-b02d-fdf6d2f2c0d1input1_00009.jpg === ERROR :23 | The operation has timed out
C:UsersjfcoteAppDataLocalTempd1785720-afc6-4822-b02d-fdf6d2f2c0d1input2_00008.jpg --- TOTALTIME:526
C:UsersjfcoteAppDataLocalTempd1785720-afc6-4822-b02d-fdf6d2f2c0d1input2_00008.jpg --- END : 2011-10-27 08:16:50
C:UsersjfcoteAppDataLocalTempd1785720-afc6-4822-b02d-fdf6d2f2c0d1input1_00012.jpg --- TOTALTIME:461
C:UsersjfcoteAppDataLocalTempd1785720-afc6-4822-b02d-fdf6d2f2c0d1input1_00012.jpg --- END : 2011-10-27 08:16:50
C:UsersjfcoteAppDataLocalTempd1785720-afc6-4822-b02d-fdf6d2f2c0d1input1_00015.jpg --- TOTALTIME:780
C:UsersjfcoteAppDataLocalTempd1785720-afc6-4822-b02d-fdf6d2f2c0d1input1_00015.jpg --- END : 2011-10-27 08:16:50
C:UsersjfcoteAppDataLocalTempd1785720-afc6-4822-b02d-fdf6d2f2c0d1input1_00011.jpg --- TOTALTIME:49
C:UsersjfcoteAppDataLocalTempd1785720-afc6-4822-b02d-fdf6d2f2c0d1input1_00011.jpg --- END : 2011-10-27 08:16:50
C:UsersjfcoteAppDataLocalTempd1785720-afc6-4822-b02d-fdf6d2f2c0d1input2_00009.jpg --- TOTALTIME:133
C:UsersjfcoteAppDataLocalTempd1785720-afc6-4822-b02d-fdf6d2f2c0d1input2_00009.jpg --- END : 2011-10-27 08:16:50
C:UsersjfcoteAppDataLocalTempd1785720-afc6-4822-b02d-fdf6d2f2c0d1input2_00007.jpg --- TOTALTIME:140
C:UsersjfcoteAppDataLocalTempd1785720-afc6-4822-b02d-fdf6d2f2c0d1input2_00007.jpg --- END : 2011-10-27 08:16:51
C:UsersjfcoteAppDataLocalTempd1785720-afc6-4822-b02d-fdf6d2f2c0d1input1_00013.jpg === ERROR :28 | The operation has timed out
C:UsersjfcoteAppDataLocalTempd1785720-afc6-4822-b02d-fdf6d2f2c0d1input2_00010.jpg --- BEGIN : 2011-10-27 08:16:56
Комментарии:
1. Вы уверены, что это тайм-аут HTTP? Возможно, это связано с частью ResponseStream вашего кода.
2. Какое фактическое исключение вы видите?
3. Это консольное приложение, веб-служба и т. Д.?
Ответ №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
может быть поврежден, если это не какой-то потокобезопасный список.
Комментарии:
1. Привет! По вашему наблюдению, это была урезанная версия журнала, в которой отсутствовала некоторая информация. Но я нашел проблему, и вы были правы в своем редактировании: ServicePointManager использовался в одном потоке, но не в другом. Когда одновременно выполнялось более 2 соединений (значение по умолчанию), оно отправляло тайм-аут. Большое спасибо, что указали на это.