Конференция "Сети" » Прием большого потока данных по UDP
 
  • MBo © (31.01.08 07:26) [0]
    Задача следующая - некий спецдевайс передает по сети по протоколу UDP данные (видеопоток), порядка 11 мегабайт в секунду, пакет 770 байт - строка. Прием занимает очень значительную часть процессорного времени (применяется WSA-функции + RecvFrom, также пробовал использовать Indy и ICS), причем, если программа занимается еще чем-то, то пакеты, приходящие  в этот момент, теряются. Например, если после приема кадра отрисовывать его, то несколько первых строк следующего кадра не принимаются.

    Можно ли предпринять какие-то меры к улучшению ситуации?
    C сетями ранее не работал, так что могут помочь любые идеи.
  • ketmar © (31.01.08 08:53) [1]
    собирать на отдельном сервере.
    поднять приоритеты получалке.
    настучать в тыкву авторам передавалки.

    %-)
  • Сергей М. © (31.01.08 08:55) [2]

    > если программа занимается еще чем-то


    Сделай так чтобы она занималась только этим и ничем более
  • MBo © (31.01.08 09:11) [3]
    т.е., такое потребление ресурсов и потери пакетов -  это нормальная ситуация?
  • Anatoly Podgoretsky © (31.01.08 09:13) [4]
    > MBo  (31.01.2008 07:26:00)  [0]

    Для такого потока нужен уже 1 гигабит, 11 мегабайт в секунду можно передать только в тепличных условиях.
  • ketmar © (31.01.08 09:26) [5]
    >[3] MBo ©(31.01.08 09:11)
    для UDP — да. оно ж лежит в буфере только пока новое не притащат. да и не факт, что старое дойдёт. потеряется по дороге — и всё.
  • MBo © (31.01.08 09:43) [6]
    >11 мегабайт в секунду можно передать только в тепличных условиях
    судя по снифферу, в стомегабитной локалке до машины пакеты доходят все, да и если программа не занимается обсчетом/отрисовкой, то она их все принимает.

    >оно ж лежит в буфере
    насчет размера буфера я пока не разобрался. В ICS и в Indy можно выставить размер буфера, который, как я понимаю, отвечает за максимальный размер пакета. А есть ли еще какие-то возможности указать сетевой подсистеме винды, чтобы побольше непрочитанных еще пакетов накапливалось?
  • ketmar © (31.01.08 09:48) [7]
    >[6] MBo ©(31.01.08 09:43)
    а максимальный размер пакета, афаир, всё равно 64к. и очереди в UDP нет. не успал поймать — кранты тому, что лежало.
  • Сергей М. © (31.01.08 09:51) [8]

    > MBo ©   (31.01.08 09:43) [6]


    см. SetSockOpt(..SO_RCVBUF..)

    Но это не спасет, если выборка из буфера стабильно медленней, чем запись в буфер.
  • Anatoly Podgoretsky © (31.01.08 09:52) [9]
    > MBo  (31.01.2008 09:43:06)  [6]

    судя по снифферу, в стомегабитной локалке до машины пакеты доходят все, да и если программа не занимается обсчетом/отрисовкой, то она их все принимает.

    Этого не должно быть, что то неправильно, в программе конечно.
    Но я бы все таки задумался 11 мегабайт это на пределе возможностей 100 мб сети. Не каждая машина и сетевая карта в состоянии обеспечить.
    А для процессора это ничто, доли процента.

    Но сам протокол UDP не обеспечивает гарантированой доставки. Размер пакета надо снижать до минимума и делать буферизации, часть буферизации делает система.
  • Сергей М. © (31.01.08 09:53) [10]

    > MBo ©


    Выноси транспортную логику в отдельный поток, повысь ему приоритет до разумных пределов.
  • ketmar © (31.01.08 09:58) [11]
    >[10] Сергей М. ©(31.01.08 09:53)
    так нечестно, я это уже посоветовал! %-)
  • MBo © (31.01.08 10:11) [12]
    да, прием ведется в отдельном потоке, повышение приоритета частично помогает, но полностью проблему не снимает.
  • ketmar © (31.01.08 10:19) [13]
    >[12] MBo ©(31.01.08 10:11)
    ну, ты учти, что поток не может быть особо приоритетней приложения. подними ещё приоритет самому приложению. другим потокам приоритет поспускай.

    а лучше таки накапливай где-то на отдельном сервере и с него уже забирай. и на гигабитке, желательно.
  • MBo © (31.01.08 10:37) [14]
    > лучше таки накапливай где-то на отдельном сервере и с него уже забирай. и на гигабитке, желательно

    Увы, не получится - в реальности будут полевые условия, железка - кабель - ноутбук.
  • Сергей М. © (31.01.08 10:54) [15]

    > MBo ©   (31.01.08 10:37) [14]


    Ты бы код своего транспортного алгоритма показал ..
  • ketmar © (31.01.08 11:23) [16]
    >[15] Сергей М. ©(31.01.08 10:54)
    я подозреваю, что ничего там такого нет. тупо сетка успевает впритык.

    однако ж глянуть не помешает в любом случае, да.
  • MBo © (31.01.08 13:52) [17]

    инициализация в конструкторе потока

     if WSAStartup($0202, WSAD) <> 0 then
       Exception.Create('WSAStartup Error');
     Ud := Socket(AF_INET, Sock_Dgram, 0);
     if INVALID_SOCKET  = Ud then
       Exception.Create('Socket Create Error');
     Addr.sin_family := PF_Inet;
     Addr.sin_addr.S_addr := Inet_Addr('0.0.0.0');
     Addr.sin_port := HtoNS(FPort);
     FillChar(Addr.sin_zero, SizeOf(Addr.sin_zero), 0);
     if Bind(UD, Addr, SizeOf(Addr)) = Socket_Error then
       Exception.Create('Socket Bind Error');

    поточная функция

     Len := 770;
     while not Terminated do begin
       FromLen := SizeOf(TSockAddr);
       WSResult := RecvFrom(UD, LineBuf, Len, 0, Addr, FromLen);
       Wrd := Swap(PWord(@LineBuf[0])^);
       LineNum := Wrd and $3FF;
       CadrNum := (Wrd shr 12) and 1;

       if LineNum = 0 then begin
         Inc(FrameCount);
         PostMessage(Form3.Handle, WM_USER, FrameCount and $F, CadrNum xor 1);
       end;

       Move(LineBuf[2], Buf[CadrNum, LineNum, 0], Wdt);
     end;

    Buf - 2 массива, один заполняется, предыдущий отрисовывается

    в обработчике WM_USER отрисовка
     SetDiBitsToDevice(Canvas.Handle, 0, 0, Wdt, Hgt, 0, 0, 0, Hgt,
       @Buf[M.LParam], PBitmapInfo(@Info)^, DIB_RGB_COLORS);


  • ketmar © (31.01.08 14:11) [18]
    у-у-у. PostMessage… да ещё и SetDiBits… есть (ничем не обоснованое, правда) мнение, что:
    эту фигню надо тихонько совать в буфер моска сразу по получении. раз.
    наладить frame skiping, если не успевает отрисоваться, а в буферг гадит.
    рисовать директиксом на оверлеях (тут, возможно, вылезут тормоза с преобразованием цветовых пространств, искать карты, оверлеи на которых потянут rgb).

    да, это: присылает, как я понял, не твоя программа, так что вправить моск именно ей никак?
  • MBo © (31.01.08 14:32) [19]
    >PostMessage… да ещё и SetDiBits
    Отрисовку, временно забыв об опасностях обращения к основному окну из доп. потока, можно вести и прямо из потока, ничего принципиально это не меняет.
    SetDiBitsToDevice  - оказался в данном случае наименее затратный способ из испытанных (альтернатива, например - формирование битмапа, происходит дольше)

    насчет DirectX - еще не прорабатывал, побоялся затрат времени на преобразование цветов.
  • Сергей М. © (31.01.08 15:16) [20]

    > один заполняется, предыдущий отрисовывается


    А если отрисовка медленней заполнения ?
    Подумай ...
  • Anatoly Podgoretsky © (31.01.08 15:41) [21]
    > MBo  (31.01.2008 14:32:19)  [19]

    Для испытания временно отключи отрисовку.
  • MBo © (31.01.08 15:47) [22]
    >А если отрисовка медленней заполнения ?
    тогда бы я ставил в очередь и отрисовывал бы только часть кадров.

    В данном случае хватает двух буферов.
    14400 пакетов в секунду, 0.07 мс один пакет
    Отрисовка сначала у меня происходила более сложно, и занимала 3-4 мс, это по времени порядка 60 пакетов, около 40 КБ данных.
    Визуально - если критерий отрисовки - приход нулевой строки, то в районе 20-50 строк было много выпавших.
    Сейчас отрисовка быстрее, и артефактов на моей машине (Athlon 3500) практически нет, но на машинах вдвое медленнее - все-таки появляются.

    Собственно, интересно - так и должна машина нагружаться при приеме из сети потока такой интенсивности, или руки нужно выпрямлять?

    (С цифрового видеограббера без проблем принимаю, достаточно сложным образом обрабатываю и отрисовываю втрое-вчетверо больший поток)
  • Anatoly Podgoretsky © (31.01.08 16:28) [23]
    > MBo  (31.01.2008 15:47:22)  [22]

    100 мегабит это ничто для процессора, проблема не в количестве, а в другом месте.
  • MBo © (31.01.08 18:31) [24]
    >а в другом месте.
    Вот и хочется понять, что это за место ;)
  • Anatoly Podgoretsky © (31.01.08 20:05) [25]
    > MBo  (31.01.2008 18:31:24)  [24]

    Э, ну ты даешь, программа то у тебя, задача сложная, явно не для форума, да и сеть у тебя работает за пределами возможностей. 11 мб не любая сеть обеспечит, а еще твоя обработка.
    Так что придется тебе самому грызть.
  • DVM © (31.01.08 23:58) [26]

    > MBo ©

    А что за девайс такой? IP камера? Просто знакомая мне тематика.
  • DVM © (01.02.08 00:01) [27]

    > Собственно, интересно - так и должна машина нагружаться
    > при приеме из сети потока такой интенсивности, или руки
    > нужно выпрямлять?

    Нет, не должна. Вся нагрузка возникает, если в принимаемом потоке надо. что то искать, выцеплять, декодировать. Отрисовка это тоже мелочи.
  • Slym © (01.02.08 04:51) [28]
    procedure x;
    type
     TLineRec=packed record
       Info:word;
       Data:array[0..192*4-1] of char;
     end;
    var
     Bitmap:TBitmap;
     Line:TLineRec;
     FromLen,LineNum,CadrNum,Wrd:integer;
     WSResult:integer;
     UD:TSocket;
     Addr:TSockAddr;
    begin
     Bitmap:=TBitmap.Create;
     try
       Bitmap.PixelFormat:=pf32bit;
       Bitmap.Width:=192;
       Bitmap.Height:=192;
       while not Terminated do begin
         FromLen := SizeOf(TSockAddr);
         WSResult := RecvFrom(UD, Line, SizeOf(Line), 0, Addr, FromLen);
         if WSResult<>SizeOf(Line) then continue;
         Wrd := Swap(Line.Info);
         LineNum:= Wrd and $3FF;
         if (LineNum>-1) and (LineNum<Bitmap.Height) then
           Move(Line.Data,Bitmap.ScanLine[LineNum]^,SizeOf(Line.Data));

         if LineNum = Bitmap.Height-1 then
         begin
           Inc(FrameCount);
           FCanvas.Lock;
           try
             FCanvas.Draw(0,0,Bitmap);
           finally
             FCanvas.Unlock;
           end;
         end;
       end;
     finally
       Bitmap.Free;
     end;
    end;

  • ага (03.02.08 11:46) [29]
    2 MBo ©

    WSARecv c кучей буферов сразу под весь кадр не пробовал? Те буфер один, но разбит на несколько, по числу строк.

    Синхронизацию сообщениями я бы выкинул. Как и многопоточность, скоре всего, использовал бы асинхронный режим. В любом случае, синхронизация здесь - лишние потери, имхо. Два буфера, один рисуется, второй принимается. Буферы переключает "приемник", а по WM_PAINT выводится "рисуемый", независимо от того, было ли обновление.

    Как гипотеза - может вывод через DirectX побыстрее будет. Не знаю, не спец.
  • Slym © (04.02.08 05:13) [30]
    если картинка боле менее статичная, то потеря небольшого колва, каждый раз разных, строк не должна вызывать видимых артефактов...
    если конечно старый кадр не затирать "чернухой", а оставлять отображая новый "поверх" старого
 
Конференция "Сети" » Прием большого потока данных по UDP
Есть новые Нет новых   [134431   +14][b:0][p:0.003]