Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Работа с сетью в Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 08.10.2012, 11:55   #1
olikke
 
Регистрация: 22.03.2010
Сообщений: 8
По умолчанию получение видео по idHttp. Зависший поток.

Здавствуйте!

Задача:
Есть несколько IP камер Axis (P1344) и бесконечное количество клиентов для них. Клиент может подключиться к любой из камер, а также к нескольким из них.
Поскольку к камерам напрямую подключаться нельзя, нужно создать что-то типа видеосервера. В задачу видеосервера входит получение от всех камер видеопотока по http и выдача их в сеть клиентам (UDP Broadcast - все клиенты в одной локальной сети).
Как делаю:
Для каждой камеры создаётся свой экземпляр TThread, внутри которого живёт idHTTP. Ну и естественно свой UDPClient (тоже использую Indy10).

Собственно код потока для HTTP:

PHP код:
unit THttp;

interface

uses
  Windows
,Classes,SysUtils,IdHTTP,SyncObjs,UDP;

type
  TSt 
= class(TThread)
  private
    
idHTTP1:TidHTTP;
    
UDPClient1:TUDP;
    
xStreamTStream;
  protected
    function 
LiveStreamWrite(const aBufferaCountLongint): Longint;
    
procedure Executeoverride;
  public
    
URL:String;
    
Numb:byte;
    
FEvent:TEvent;
  
end;

implementation
uses
  LiveStreamer
,Global;

procedure TSt.Execute;
begin
  FreeOnTerminate
:=true;
  
idHTTP1:=TidHTTP.Create(nil);
  
idHTTP1.Request:=TidHTTPRequest.Create(idHTTP1);
  
idHTTP1.Request.BasicAuthentication:=true;
  
idHTTP1.Request.Password:='****';
  
idHTTP1.Request.Username:='****';
  
idHTTP1.HTTPOptions:=[hoForceEncodeParams];
  
idHTTp1.Request.Connection:='Keep-Alive';
  
UDPClient1:=TUDP.Create(True);
  
UDPClient1.Priority:=tpNormal;
  
UDPClient1.FreeOnTerminate:=True;
  
UDPClient1.Port:=Table[Numb].Port;
  
UDPClient1.Numb:=Numb;
  
UDPClient1.Resume;
  
xStream := TLiveStream.Create(nilLiveStreamWrite);
  
xStream.Size:=$8800;
  
XStream.Position:=0;
  while (
not fl_STOP) and (not fl_st[Numb]) do
  
begin
    
try idHTTP1.Get(URLxStream);
    finally  
end;
  
end;
  
FreeAndNil(xStream);
  
UDPCLient1.Terminate;
  
Event[numb].Setevent;
  
UDPClient1:=nil;
end;



function 
TSt.LiveStreamWrite(const aBufferaCountInteger): Longint;
begin
    Buffer
[Numb].Lock;
  try
    
Buffer[Numb].Size:=0;
    
Buffer[Numb].Write(aBuffer,aCount);
    
Buffer[Numb].Position:=0;
  finally
    
Buffer[Numb].UnLock;
  
end;
  
Event[Numb].SetEvent;
end;

end
Код потока для UDP:

PHP код:
unit UDP;

interface

uses
  Classes
,IdUDPClient,IdGlobal,SyncObjs,SysUtils;

type
  TUDP 
= class(TThread)
  private
    
UDPClient:TidUDPClient;
  protected
    
procedure Executeoverride;
  public
    
Port:integer;
    
HOST:string;
    
Numb:byte;
  
end;


implementation

uses 
Global;


procedure TUDP.Execute;
var 
buff:string;
begin
  FreeOnTerminate
:=true;
  
//Создание клиента для передачи данных
  
UDPClient:=TIdUDPClient.Create;
  
UDPClient.BufferSize:=$8800;
  
UDPClient.IPVersion:=Id_IPv4;
  
UDPClient.Port:=Port;
  
UDPClient.ReceiveTimeout:=-1;
  
UDPClient.Tag:=0;
  
UDPClient.BroadcastEnabled:=true;
  
UDPClient.Host:=Table[Numb].Broadcast;
  try 
UDPClient.Active:=True;
  
except end;
  while 
not Terminated do
  
begin
    Event
[Numb].WaitFor(INFINITE);
    
Event[Numb].ResetEvent;
    if 
terminated then
    begin
      UDPClient
.Active:=false;
      
UDPClient.Free;
      
buff:='';
      exit;
    
end;
    
buff:='';
      
Buffer[Numb].Lock;
    try
      
Buff:=Buffer[Numb].DataString;
    finally
      
Buffer[Numb].UnLock;
    
end;
    try 
UDPClient.Send(TRIM(Table[Numb].Broadcast),UDPClient.Port,buff);
    
except
    end
;
    
buff:='';
  
end;
end;

end
Так вот, вся эта зараза прекрасно работает. Клиенты смотрят картинки с камер.
Но где-то через час-два каринтка пропадает. Точнее от IP камеры пропадает поток (смотрела сниффером). А значит экземпояр потока TSt, привязанного к этой камере бесконечно ждёт продолжения кино (фактически висит).

У меня два вопроса:
1. Почему пропадает поток от IP камеры (мой косяк или её?)
2. Как мне грамотно прибить поток висящий? Кроме TerminateThread до него ничем не достучаться. Но в этом случае все мои ресурсы остаются незакрытыми. Да и неправильно это как-то....

СПАСИТЕ МЕНЯ!!!
olikke вне форума Ответить с цитированием
Старый 08.10.2012, 12:33   #2
саша40
Участник клуба
 
Регистрация: 12.09.2012
Сообщений: 1,030
По умолчанию

Причиной пропадание патока может быть даже обычное нарушение связи или некачественое соединение. Это решается докачкой.
Что нужно программисту: Компьютер, Среда программирование, Воображение, Прямые руки, Мозги, Знания этой среды программирования.
Программист-это профессия, а программирование-это моё хобби.
саша40 вне форума Ответить с цитированием
Старый 08.10.2012, 13:45   #3
olikke
 
Регистрация: 22.03.2010
Сообщений: 8
По умолчанию

саша40, как это обработать?
olikke вне форума Ответить с цитированием
Старый 08.10.2012, 16:12   #4
raxp
Старожил
 
Регистрация: 29.09.2009
Сообщений: 9,713
По умолчанию

...а что это за LiveStreamer-юнит? Из какого SDK (в Axis SDK я такого не видел) или самописный модуль?
Разработки и научно-технические публикации :: Видеоблог :: Твиттер
Radar systems engineer & Software developer of industrial automation
raxp вне форума Ответить с цитированием
Старый 08.10.2012, 16:17   #5
саша40
Участник клуба
 
Регистрация: 12.09.2012
Сообщений: 1,030
По умолчанию

Цитата:
Сообщение от olikke Посмотреть сообщение
саша40, как это обработать?
не знаю. Как-то обрабатывается.
Что нужно программисту: Компьютер, Среда программирование, Воображение, Прямые руки, Мозги, Знания этой среды программирования.
Программист-это профессия, а программирование-это моё хобби.
саша40 вне форума Ответить с цитированием
Старый 08.10.2012, 17:25   #6
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,426
По умолчанию

Я бы тоже завис после такого...
Код:
  while not Terminated do
  begin
    Event[Numb].WaitFor(INFINITE);
    Event[Numb].ResetEvent;
    if terminated then
Где конструкторы классов? Где try finally блоки?

Переработал ваш UDP трэд:
Код:

constructor TUDP.Create;
begin
  inhereited Create(True);
  FreeOnTerminate:=true;
  UDPClient:=TIdUDPClient.Create;
  UDPClient.BufferSize:=$8800;
  UDPClient.IPVersion:=Id_IPv4;
  UDPClient.Port:=Port;
  UDPClient.ReceiveTimeout:=-1;
  UDPClient.Tag:=0;
  UDPClient.BroadcastEnabled:=true;
  UDPClient.Host:=Table[Numb].Broadcast;
and;


destructor TUDP.Destroy; override;
begin
   UDPClient.Active:=false;
   UDPClient.Free;
inhereited;
and;


procedure TUDP.Execute;
var buff:string;
begin
  UDPClient.Active:=True; //Зачем try except если исключение не обрабатывается. Плохо так делать.. 
  while not Terminated do
  begin
   if  Event[Numb].WaitFor(INFINITE) = wrSignaled then
   begin
    if terminated then
     break;
         buff:='';
     
    try
      Buffer[Numb].Lock;
      Buff:=Buffer[Numb].DataString;
    finally
      Buffer[Numb].UnLock;
    end;
   UDPClient.Send(TRIM(Table[Numb].Broadcast),UDPClient.Port,buff); //Зачем try except если исключение не обрабатывается. Плохо так делать.. 
   Event[Numb].ResetEvent; //Wait for next signal state
   end; //Event end
  end;
end;
После увиденного кода, косяк ваш. И не один..
Цитата:
1. Почему пропадает поток от IP камеры (мой косяк или её?)
Где блоги try finally? Где конструкторы и деструкторы потоков?

Где обработка try except?(У вас она есть, НО вы же никак не знаете о том, что исключение поймано, и что за оно - вы тоже не знаете. Лог чтоль прикрутите...).
Кстати очевидно же, это есмъ причина сего:
Цитата:
Но где-то через час-два каринтка пропадает.
Цитата:
2. Как мне грамотно прибить поток висящий? Кроме TerminateThread до него ничем не достучаться. Но в этом случае все мои ресурсы остаются незакрытыми. Да и неправильно это как-то....
Код:
TMyThreead.Event[Numb].SetEvent;  //Поток получает сигнал
TMyThreead.Terminate;  //Terminated = true, поток выскочит из цикла while not terminated
TMyThreead.WaitFor;  //Основной поток ждет завершения дополнительного
в дополнение:
Код:
 UDPClient.ReceiveTimeout:=-1;
Т.е. таймаута нет? Вы 100% уверены что не будет обрыва на линии, что не будет потери пакетов? Что сервер не перезагрузят? А то ведь, бесконечно ждать будите с таким свойством
Плохая идея TEvent глобальным делать, это не критическая секция. Еслион глобальный, то влияет на все TUDP одновременно.

Последний раз редактировалось Человек_Борща; 08.10.2012 в 17:46.
Человек_Борща вне форума Ответить с цитированием
Старый 08.10.2012, 18:28   #7
olikke
 
Регистрация: 22.03.2010
Сообщений: 8
По умолчанию

Цитата:
...а что это за LiveStreamer-юнит? Из какого SDK (в Axis SDK я такого не видел) или самописный модуль?
К сожалению за давностью лет не помню автора:

Код:

unit LiveStreamer;

interface

uses
  Classes;

type
  TLSOnRead = function(var vBuffer; aCount: Longint): Longint of object;
  TLSOnWrite = function(const aBuffer; aCount: Longint): Longint of object;

  TLiveStream = class(TStream)
  protected
    fOnRead: TLSOnRead;
    fOnWrite: TLSOnWrite;
    // We dont override and just ignore SetSize. Some callers might try to preallocate
    // size. Because of this we just ignore instead of throwing an error.
    // procedure SetSize(NewSize: Longint); override;
    // procedure SetSize(const NewSize: Int64); override;
  public
    constructor Create(aOnRead: TLSOnRead; aOnWrite: TLSOnWrite);
    function Read(var vBuffer; aCount: Longint): Longint; override;
    function Write(const aBuffer; aCount: Longint): Longint; override;
    // We dont implement seek either, we catch all data...
    function Seek(const aOffset: Int64; aOrigin: TSeekOrigin): Int64; override;
  end;

implementation

uses
  SysUtils;

{ TLiveStream }

constructor TLiveStream.Create(aOnRead: TLSOnRead; aOnWrite: TLSOnWrite);
begin
  inherited Create;
  fOnRead := aOnRead;
  fOnWrite := aOnWrite;
end;

function TLiveStream.Read(var vBuffer; aCount: Integer): Longint;
begin
  if Assigned(fOnRead) then begin
    Result := fOnRead(vBuffer, aCount);
  end else begin
    // If not handled, we just ignore and say we handled it all so we dont err out caller
    Result := aCount;
  end;
end;

function TLiveStream.Seek(const aOffset: Int64; aOrigin: TSeekOrigin): Int64;
begin
  // Must return 0 - ie no position. If not stack overflow becuase how TStream.Seek is
  // implemented.
  Result := 0;
end;

function TLiveStream.Write(const aBuffer; aCount: Integer): Longint;
begin
  if Assigned(fOnWrite) then begin
    Result := fOnWrite(aBuffer, aCount);
  end else begin
    // If not handled, we just ignore and say we handled it all so we dont err out caller
    Result := aCount;
  end;
end;

end.
olikke вне форума Ответить с цитированием
Старый 08.10.2012, 21:26   #8
olikke
 
Регистрация: 22.03.2010
Сообщений: 8
По умолчанию

Цитата:
Где конструкторы классов?
Вы абсолютно правы. Впишу.

Цитата:
Где обработка try except?(У вас она есть, НО вы же никак не знаете о том, что исключение поймано, и что за оно - вы тоже не знаете. Лог чтоль прикрутите...).
Кстати очевидно же, это есмъ причина сего:
Есть в исходнике у меня обработка - лог. Выкинула из примера т.к. ничего интересного они мне не показали.

Цитата:
в дополнение:

Код:

UDPClient.ReceiveTimeout:=-1;

Т.е. таймаута нет? Вы 100% уверены что не будет обрыва на линии, что не будет потери пакетов? Что сервер не перезагрузят? А то ведь, бесконечно ждать будите с таким свойством
Я ничего не жду.

Цитата:
Плохая идея TEvent глобальным делать, это не критическая секция. Еслион глобальный, то влияет на все TUDP одновременно.
У меня массив TEventov - для каждого TUDP он свой.

Цитата:
Код:

TMyThreead.Event[Numb].SetEvent; //Поток получает сигнал
TMyThreead.Terminate; //Terminated = true, поток выскочит из цикла while not terminated
TMyThreead.WaitFor; //Основной поток ждет завершения дополнительного
Я обычно пишу наоборот

Код:
TMyThreead.Terminate;  //Terminated = true, поток выскочит из цикла
TMyThreead.Event[Numb].SetEvent;  //Поток получает сигнал
 while not terminated
TMyThreead.WaitFor;  //Основной поток ждет завершения дополнительного
Но в данном случае мне это не поможет. Ведь зависает не TUDP, а TSt, в котором происходит следующее:
В TSt.Execute я дохожу до кода
Цитата:
while (not fl_STOP) and (not fl_st[Numb]) do
begin
try idHTTP1.Get(URL, xStream);
finally ... end;
end;
и остаюсь там навсегда, т.к. xStream бесконечен.
Единственная возможность завершиться (не уверена что хорошо так делать), это в функции считывания данных из буфера сделать так:

Цитата:
function TSt.LiveStreamWrite(const aBuffer; aCount: Integer): Longint;
var str:string;
begin

if fl_STOP then
begin
idHTTP1.Disconnect;
exit;
end;

Buffer[Numb].Lock;
try
Buffer[Numb].Size:=0;
Buffer[Numb].Write(aBuffer,aCount);
Buffer[Numb].Position:=0;
finally
Buffer[Numb].UnLock;
end;
Event[Numb].SetEvent;
INC(HTTPCount[Numb]);
end;
По крайней мере, когда данные по http приходят - это помогает.
Но данные от камеры просто перестают приходить.
Просматривая сниффером пакеты от камеры я видела, как в один прекрасный момент CheckSum сетевого и транспортного протокола (IP и TCP) становятся incorrect. При этом idHTTP всё также ожидает данных
Цитата:
idHTTP1.Get(URL, xStream);
а их нет - функция
Цитата:
function TSt.LiveStreamWrite(const aBuffer; aCount: Integer): Longint;
больше не вызывается никогда.
Всё что, как я понимаю, можно сделать - поставить следящий поток, и отлавливая зависания idHTTP делать TerminateThread. Но это ведь не корректно.
Завтра внесу правки, указанные Человек_Борща, но боюсь это мне не поможет....
olikke вне форума Ответить с цитированием
Старый 08.10.2012, 21:50   #9
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,426
По умолчанию

Код:
Я ничего не жду.
В этом ваша проблема.
ReciveTimeout - указывает кол-во секунд в течении которых клиент ждет хотя бы 1 байт информации от сервера, в противном случае соединение размыкается. В вашем случае клиент ждет отдачи сервера бесконечно, итог - поток висит.

Код:
У меня массив TEventov - для каждого TUDP он свой.
Не практично. Если TEvent для TThread, то пусть он будет инкапсулирован в TThread и доступен через общедоступное свойство или метод.
Какова гарантия что завтро кол-во TThread'ов не станет больше кол-ва TEvent'ов в массиве?

Цитата:
try idHTTP1.Get(URL, xStream);
finally ... end;
Цитата:
...клиент ждет хотя бы 1 байт информации от сервера, в противном случае соединение размыкается.

Последний раз редактировалось Человек_Борща; 08.10.2012 в 21:53.
Человек_Борща вне форума Ответить с цитированием
Старый 08.10.2012, 22:08   #10
olikke
 
Регистрация: 22.03.2010
Сообщений: 8
По умолчанию

Цитата:
Если TEvent для TThread, то пусть он будет инкапсулирован в TThread и доступен через общедоступное свойство или метод.
Какова гарантия что завтро кол-во TThread'ов не станет больше кол-ва TEvent'ов в массиве?
Можно, но не критично и к решению проблемы не приблизит. Количество TThread'ов определяется кол-вом камер, а оно оговорено в ТЗ.

Цитата:
В этом ваша проблема.
ReciveTimeout - указывает кол-во секунд в течении которых клиент ждет хотя бы 1 байт информации от сервера, в противном случае соединение размыкается. В вашем случае клиент ждет отдачи сервера бесконечно, итог - поток висит.
Да не висит он. У меня есть уже готовые клиенты для UDP потока, которые на локальных машинах прекрасно принимают, декодируют и смотрят поток от tUDP. И речь идёт не о паре-тройке посылок. За один час передаётся их порядка 324000 от каждой камеры (порядка 0,2% пропадают по дороге).
К тому же даже полное зависание tUDP (если б оно было) никак не может подвесить tST, поскольку TEvent скинут сразу, и даже из буфера Buffer[Numb] данные считываются заранее.
Просто из принципа поставлю
Код:
UDPClient.ReceiveTimeout:=0;

Последний раз редактировалось olikke; 08.10.2012 в 22:14.
olikke вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Перехват поток песен и видео (ютуб, контакт и им подобие) coNsept Общие вопросы C/C++ 14 07.02.2012 13:18
Получение ссылки скачивания видео с контакта cargo29 Работа с сетью в Delphi 6 28.05.2011 22:50
Не удается связать поток+idHttp+прогресс бар grafgrial Общие вопросы Delphi 1 24.05.2011 15:46
Поток видео и аудио с камеры HarPy Мультимедиа в Delphi 0 04.03.2009 09:05