Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: LwIP факт отправки UDP пакета
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы > Программирование
Real_Bastard
Отсылаю больщой объем данных по UDP. Пакетами по 1000 байт. Не могу понять, как определить, готов стек к приему нового пакета или нет. Сейчас похоже слишком часто вызываю udp_send() и поэтому каждый второй пакет не доходит. Задержка помогает, но не всегда.
Код
while (1)
      {
        /* check if any packet received */
        if (ETH_CheckFrameReceived())
        {
          /* process received ethernet packet */
          LwIP_Pkt_Handle();
        }
        /* handle periodic timers for LwIP */
        LwIP_Periodic_Handle(LocalTime);
            get_new_data(data);  //получаю данные
            //delay(); //Задержка
        /* allocate pbuf from pool*/
            p = pbuf_alloc(PBUF_TRANSPORT, 1000, PBUF_POOL);
        if (p != NULL ) {
            /* copy data to pbuf */
            pbuf_take(p, (char*) data, 1000);
            /* send udp data */
            udp_send(upcb, p);
            /* free pbuf */
            pbuf_free(p);
        }
      }
scifi
Я бы проверял возвращаемое значение функции udp_send().
Golikov A.
факта отсылки пакета нет и быть не может.
Единственное что вы можете получить это то что на него выделен буфер и он добавлен в очередь отправки, а отправка произойдет во время обработки основной функции стэка. А также учитывая что UDP пакетный, а не потоковый, напихав много пакетов уходить они будут по очереди с каждым новым вызовом этой функции
scifi
Цитата(Golikov A. @ Dec 9 2013, 10:33) *
факта отсылки пакета нет и быть не может.

Неправда. Я специально проследил порядок выполнения udp_send(). Он ведёт прямиком к netif->linkoutput, то есть непосредственно к функции отправки пакета драйвером. Естественно, при условии, что arp уже сделал свои дела. Понятно, что драйвер может буферизировать пакеты перед отправкой, но не обязательно. У меня, к примеру, не буферизирует, а сразу отправляет.
Real_Bastard
Цитата(scifi @ Dec 9 2013, 10:07) *
Я бы проверял возвращаемое значение функции udp_send().
Пробовал. Не помогает. Она на каждый вызов отвечает ОК. А пакеты выходят через один. С задержкой теряются, но 1 из 1000.
megajohn
"буферизируются или нет", это называются Блокирующие ( синхронные ) или неблокирующие ( ассинхронные ) сокеты =)

обычно задается на этапе компиляции или же при создании сокета ( если правда поддерживается стеком )
так что поищите в настройках lwIP

и кстати, "теряются" вы судите по приемной стороне или по WireShark ?

если приемная сторона не успевает обрабатывать, то это проблема никак не относится к передающей стороне. На то он и UDP
Real_Bastard
Ну приемное приложение у меня самописное и корявое, но 80-90Мбит\с принимает. В каждый пакет пихаю номер и инкрементирую. Без задержки почти сплошняком теряется каждый второй пакет. Поток при этом тот-же 80-90. А вот с введением задержки перед функцией отправки, потери уменьшаются до 1 из 1000. Поток не меняется.
Golikov A.
блокирующий и не блокирующий - это разве не к операционке относится? LwIP может и без нее фигачить...

сейчас поглядел на UDP посылку, вызывая целую кучу функций одну за другой походу дела склеивает пакеты, добавляет заголовки, а потом правда пихает это все прямиком на выход. Как то я упустил этот момент, извиняюсь, правда обманул.

Другое дело что по ходу этих функций есть кучу мест на которых процесс может прерваться и оно все вывалиться, но вываливается оно с кодами ошибок и отладочными сообщениями. Даже последняя функция выдачи наружу тоже возвращает код ошибки.

Так что если send_UDP вернуло ок, то до драйвера сообщение дошло, и наверняка во все буферы (если они дальше есть) добавилось и до выхода дойдет.


megajohn
[quote name='Golikov A.' date='Dec 9 2013, 13:56' post='1217234']
> А вот с введением задержки перед функцией отправки, потери уменьшаются до 1 из 1000. Поток не меняется.
это как так: увеличили период отправки а поток не изменился ?

>блокирующий и не блокирующий - это разве не к операционке относится?
операционка задат лишь приоритет задач, и их переключение. А ждать завершения отправки по физическому каналу это уже другое

на пальцах:
*data_reg = 'a'; *data_reg = 'b';
или
*data_reg = 'a'; while( data_reg_busy() ); *DATA_REG = 'b'; while( data_reg_busy() );

это же элементарно, Ватсон. Единствено что в армах это индекс управляющей структуры
Golikov A.
Цитата(Real_Bastard @ Dec 9 2013, 13:53) *
Ну приемное приложение у меня самописное и корявое, но 80-90Мбит\с принимает. В каждый пакет пихаю номер и инкрементирую. Без задержки почти сплошняком теряется каждый второй пакет. Поток при этом тот-же 80-90. А вот с введением задержки перед функцией отправки, потери уменьшаются до 1 из 1000. Поток не меняется.


надо шарком проверить, есть ли на интерфейсе те пакеты что не дошли до приложения...

Цитата(megajohn @ Dec 9 2013, 14:14) *
на пальцах:
*data_reg = 'a'; *data_reg = 'b';
или
*data_reg = 'a'; while( data_reg_busy() ); *DATA_REG = 'b'; while( data_reg_busy() );

это же элементарно, Ватсон. Единствено что в армах это индекс управляющей структуры


Это правда элементарно
Real_Bastard
Цитата(megajohn @ Dec 9 2013, 14:14) *
> А вот с введением задержки перед функцией отправки, потери уменьшаются до 1 из 1000. Поток не меняется.
это как так: увеличили период отправки а поток не изменился ?
А чего ему меняться, если у нас канал 100Мбит. А я от него больше пытаюсь выжать. вот пакеты и исчезают. А с задержкой как раз 100 и выходит.


Цитата(Golikov A. @ Dec 9 2013, 14:26) *
надо шарком проверить, есть ли на интерфейсе те пакеты что не дошли до приложения...

Если бы каждый потерянный пакет до интерфейса доходил, то поток был бы сильно за сотню. а он и так около 90, при том что примерно половины пакетов нет.
Но шарк запущу. А вдруг.....
megajohn
Цитата(Real_Bastard @ Dec 9 2013, 15:05) *
А чего ему меняться, если у нас канал 100Мбит.


я бы назвал это пропускной способностью. А поток это уже ваши данные.
Golikov A.
то есть задача стоит как ограничить свои данные на выход, чтобы не засрать канал?

ну если не ТСР, то надо добавить контроль потока в УДП. Подтверждать получение, фактически перейти на ТСР...

scifi
Цитата(megajohn @ Dec 9 2013, 13:38) *
"буферизируются или нет", это называются Блокирующие ( синхронные ) или неблокирующие ( ассинхронные ) сокеты =)

Знаете, что такое "lwip raw API", pbuf_alloc() и udp_send()? Там сокетами и не пахнет.

Цитата(Golikov A. @ Dec 9 2013, 17:00) *
то есть задача стоит как ограничить свои данные на выход, чтобы не засрать канал?
ну если не ТСР, то надо добавить контроль потока в УДП. Подтверждать получение, фактически перейти на ТСР...

Не обязательно. Можно на уровне Ethernet MAC собирать информацию (пакет ушёл или не ушёл) и передавать в приложение. Это можно делать в обход lwip (скажем, через глобальные переменные). Некрасиво, но можно попробовать.
Real_Bastard
Запустил шарк. 45 000 пакетов принято. А счетчик пакетов (первые 4 байта пакета)70 000. Как-то так....

Код
    
while (1) {
    /* check if any packet received */
        if (ETH_CheckFrameReceived()) {
    /* process received ethernet packet */
         LwIP_Pkt_Handle();
    }
    /* handle periodic timers for LwIP */
    LwIP_Periodic_Handle(LocalTime);
    /* allocate pbuf from pool*/
    p = pbuf_alloc(PBUF_TRANSPORT, 1000, PBUF_POOL);
    if (p != NULL) {
        /* copy data to pbuf */
        pbuf_take(p, (char*) data, 1000);
        /* send udp data */
        if (udp_send(upcb, p) == ERR_OK) {
            PacketCount++;
                        data[0] = (PacketCount >> 24) & 0x000000FF;
            data[1] = (PacketCount >> 16) & 0x000000FF;
            data[2] = (PacketCount >> 8) & 0x000000FF;
            data[3] = (PacketCount) & 0x000000FF;
            //Delay_xx(500);
        }
    /* free pbuf */
    pbuf_free(p);
    }
}



Цитата(scifi @ Dec 9 2013, 18:15) *
Можно на уровне Ethernet MAC собирать информацию ... Некрасиво, но можно попробовать.

очень не хочется...но возможно это будет самый простой вариант.
scifi
Цитата(Real_Bastard @ Dec 9 2013, 19:33) *
очень не хочется...но возможно это будет самый простой вариант.

Да, забыл: весьма вероятно, что драйвер тупо игнорирует ошибку и не передаёт код наверх. Часто эти драйверы пишут левой ногой. Так что попробуйте в нём разобраться.
Real_Bastard
Цитата(scifi @ Dec 9 2013, 21:33) *
весьма вероятно, что драйвер тупо игнорирует ошибку и не передаёт код наверх. Часто эти драйверы пишут левой ногой. Так что попробуйте в нём разобраться.

ОНО самое!!! Функция udp_send утыкается в функцию low_level_output() (порт STM32).
Цитата
/**
* This function should do the actual transmission of the packet.....
* @return ERR_OK if the packet could be sent
* an err_t value if the packet couldn't be sent
*
* @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
* strange results. You might consider waiting for space in the DMA queue
* to become availale since the stack doesn't retry to send a packet
* dropped because of memory failure (except for the TCP timers).
*/

В общем ждать она не ждет, и всегда отсылает ОК.
Увеличил размер буфера до 1200 байт, чтоб мой килобайт влез, и не надо было разбивать его на части. low_level_output() научил для начала возвращать ошибку. Стало почти хорошо. пакеты теряются один раз из 6 000-10 000, но сразу по несколько. Итого на 100МБайт теряется 100-200К. Поток 93 Мбит\сек.
sergey sva
Если это видео может как то сжимать его перед отправкой.
Real_Bastard
Цитата(sergey sva @ Dec 12 2013, 16:51) *
Если это видео может как то сжимать его перед отправкой.

Да не. С исправленным драйвером вроде все ОК. около 90Мбит\с выдает без потерь.
TU-104
Цитата(scifi @ Dec 9 2013, 12:57) *
Неправда. Я специально проследил порядок выполнения udp_send(). Он ведёт прямиком к netif->linkoutput, то есть непосредственно к функции отправки пакета драйвером. Естественно, при условии, что arp уже сделал свои дела. Понятно, что драйвер может буферизировать пакеты перед отправкой, но не обязательно. У меня, к примеру, не буферизирует, а сразу отправляет.

а всё-таки, только так? Вызвать udp_send и проверять по коду ошибки? Может, есть какой-то флаг готовности?
Посмотрел свой low_level_output, проверка есть: пытается распихать в пакет по буферам DMA и при невозможности возвращает ошибку. Конкретно в моём примере выделено 4 буфера размером 1524 байта. Значит, больше никак не узнать, только проверять есть ли место.
Может кто разбирался, еще вопросик: эти 4 буфера под 4 ЛЮБЫХ пакета? 4 пакета по 1500 байт, или 4 пакета по 100 байт...
kolobok0
Цитата(TU-104 @ Apr 14 2016, 14:25) *
а всё-таки, только так?... эти 4 буфера под 4 ЛЮБЫХ пакета? 4 пакета по 1500 байт, или 4 пакета по 100 байт...


согласно RFC функция передачи юдп гарантирует отправку. Т.е. если вам вернули код ошибки ОК - то пакет гарантировано дошёл до трансформатора
Вашего передатчика. Так по стандарту.

Буфера - тут такое дело. По идее размеры резервирования прописываются в конфигураторе(как тут уже прозвучало). Т.е. зарезервируете 4 по 1000 = будет всего 4 кила.

С буферами в основном засада на приёме. Выделять память в драйвере - накладно очень. Но можно а) использовать заголовки ПДП старые
б) делать резервирование таких блоков - для драйвера.

(круглый)
scifi
Цитата(kolobok0 @ Apr 14 2016, 16:16) *
согласно RFC функция передачи юдп гарантирует отправку. Т.е. если вам вернули код ошибки ОК - то пакет гарантировано дошёл до трансформатора
Вашего передатчика. Так по стандарту.

Ну-ну. Осталось понять, читал ли аффтар кода эти стандарты. Угадайте, каковы шансы? biggrin.gif
kolobok0
Цитата(scifi @ Apr 14 2016, 16:21) *
..Осталось понять...


когда писал - хотел дать мысль, что реализация реализацией, но существует стандарт пользовательского(с точки зрения стэка) интерфейса.
А прочтёт если захочет по уму, от печки.

ну где то так
(круглый)
ЗЫ
Элемент иронии если только чуть-чуть sm.gif
TU-104
Цитата(kolobok0 @ Apr 14 2016, 18:16) *
согласно RFC функция передачи юдп гарантирует отправку. Т.е. если вам вернули код ошибки ОК - то пакет гарантировано дошёл до трансформатора
Вашего передатчика. Так по стандарту.

Неее, никто такой гарантии не даст, что прям до трансформатора дошло. В примере lwip stm32 - дошло да DMA и всё, а там в MII. А там еще физика....

Цитата
Буфера - тут такое дело. По идее размеры резервирования прописываются в конфигураторе(как тут уже прозвучало). Т.е. зарезервируете 4 по 1000 = будет всего 4 кила.

Поотправлял пакеты, похоже, что там(всё в том же примере драйвера) на 4 кадра зарезервировано(не важно какого размера кадр).

Цитата
С буферами в основном засада на приёме. Выделять память в драйвере - накладно очень. Но можно а) использовать заголовки ПДП старые
б) делать резервирование таких блоков - для драйвера.

А что такое ПДП? На приёме в драйвере аналогично организовано 4 буфера, каждый на 1 кадр, максимальный размер ~1500.


kolobok0
Цитата(TU-104 @ Apr 15 2016, 08:06) *
... дошло да DMA и всё, а там в MII. А там еще физика....
...похоже, что там(всё в том же примере драйвера)...что такое ПДП? ...организовано 4 буфера...


речь идёт о стандарте. т.е. если управление вернулось в вызываемую программу - значит ушло гарантированно. либо ошибка на возврате.
перепишите "драйвер" (с учётом возврата ошибки и синхронизации вызова. если считаете, что вероятность сбоя высока), делоф то...
DMA = пдп (простите, старый советский слэнг в крови) sm.gif

если присмотритесь как устроено(STM32F4xx), то там выделяются заголовки описательные(которые ставятся в очередь dma) и сами буфера выделенные под это дело.
причём на приёме автоматически разруливается наполнение этих входных буферов поставленных в кольцо. И Вы при анализе выбираете только те, которые обозначены как
уже отработанные. По коду ошибки и состоянию флагов Вы имеете цепочку пакетов с полезными данными(либо один пакет - не суть). Вам требуется
заменить эти буфера - вот именно в этом месте Вам необходимо решать следующие задачи - тупо копировать данные, либо уменьшать объём
буферов на приёме, либо заменять на новые освободившиеся блоки памяти под буфера.
Лично сам тупо заменяю блоки памяти. А беру их из специальной очереди для драйвера. Заполненные буфера - так и уходят на верхний уровень.
т.е. нет операций копирования совсем. А заголовки так и остаются стоять в кольце (после обработки естественно флаги им выставляем правильные).

как то так - давно рисовал, по памяти сейчас изложил.
(круглый)
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.