Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Вопрос по LwIP
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Petr_
Передаю большой файл.
Использую цепочку колбеков, как и задумано в lwIP.
Но заполняю буфер передачи не полностью(узнаю из tcp_sndbuf(pcb); ).
Далее вызываю tcp_write(pcb, Data_Bf, wMaxPut, 0); и завершаю функцию.
Скорость никакущая.
Смотрю что идет по сетке - FTP клиент не посылает ACK добрых 0,3 сек.
Крепко думаю - доходит, что размер окна равен 2, а пакет уходит 1.
Рою сеть.
Нахожу вариант:
Код:
Код
    pcb->flags |= TF_NODELAY;                                   //отключаем  Nagle
    tcp_write(pcb, Data_Bf, wMaxPut >> 2, 1);                   //первый пакет
    tcp_output(pcb);                                            //передать что влезло
    //второй пакет
    tcp_write(pcb, &Data_Bf[wMaxPut >> 2], wMaxPut-(wMaxPut >> 2), 1);
    tcp_output(pcb);                                            //передать что влезло (опционально)

ACK сразу вываливаются на каждую пару пакетов и скорость вырастает в сотни раз. Здорово...
Только решение кривое.
Можно конечно набивать буфер под завязку
(как криво и не полностью сделано в WEB сервере ST).
Но это крайне неудобно.
Бить данные всегда на 2 куска - тоже левизна.

Кто то знает нормальное решение?
romas2010
Цитата(Petr_ @ Mar 15 2016, 21:12) *
Передаю большой файл.
Использую цепочку колбеков, как и задумано в lwIP.
Но заполняю буфер передачи не полностью(узнаю из tcp_sndbuf(pcb); ).
Далее вызываю tcp_write(pcb, Data_Bf, wMaxPut, 0); и завершаю функцию.
Скорость никакущая.
.....
Кто то знает нормальное решение?


Ну насколько я понял из написанного,то вы сами и предложили нормальное решение,отключив алгоритм Нейгла(был такой перец,который предложил специально задерживать данные для увеличения пропускной способности сети.При этом подразумевается,что данные небольшого размера не передаются сразу в сеть,а накапливаются в буфере,и передаются только тогда,когда буфер полон)
Petr_
Цитата(romas2010 @ Mar 15 2016, 19:50) *
Ну насколько я понял из написанного,то вы сами и предложили нормальное решение,отключив алгоритм Нейгла(был такой перец,который предложил специально задерживать данные для увеличения пропускной способности сети.При этом подразумевается,что данные небольшого размера не передаются сразу в сеть,а накапливаются в буфере,и передаются только тогда,когда буфер полон)


Не совсем так. Нейгл конечно умный перец, но...
Дело не в скорости работы самого стека или прохождении пакетов по сети.

Установили соединение - вызвался SENT, готовим данные.
Если забить буфер полностью (в настройках стека это (1500-40)*2 байт)
то LwIP пошлет 2 пакета в окне равном 2 пакета.
И любая реализация TCP (пробовал в форточках и Android)
сгенерирует ACK в конце ОКНА (т.е. после второго пакета сразу)
Он будет обработан LwIP и вызовется моя SENT для подготовки новых данных.
Но если забить буфер скажем на 2000 байт или на 500 байт,
то уйдет ОДИН пакет(а окно по прежнему - 2 пакета). И на приемной стороне ACK
будет сформирован только по истечении таймаута 0.2-0.3сек.
Скажем я делаю modbus - у меня паузы будут после каждого пакета.
И забивать буфер полностью мне просто нечем.
Тупо потому, что lwIP не умеет настраивать размер окна(есть в доке).
А если применить финт с биением данных на 2 пакета принудительно (для первого отключаем ожидание ACK, второй нормальный)
то получаем ACK немедленно и скорость обмена доходит до
10-25 тыс. туда/обратно в секунду.

Просто решение корявое, хотя и рабочее. Потому спрашиваю.
aaarrr
Цитата(Petr_ @ Mar 15 2016, 23:11) *
для первого отключаем ожидание ACK, второй нормальный

В вашем примере Nagle отключается не только для первого пакета, а вообще для данного соединения.
Petr_
Цитата(aaarrr @ Mar 15 2016, 20:32) *
В вашем примере Nagle отключается не только для первого пакета, а вообще для данного соединения.


Это не так в реале!
ACK ожидается для 2-го пакета. Это вариант из Сети.
Я посмотрел исходники. Это имнно так - флаг убирается для новых пакетов (согласно дефолтным установкам)
Есть еще вариант - допилить lwIP на предмет работы с окнами.
Но тогда станет невозможным легкий апгрейд, если он когда то выйдет...
aaarrr
Цитата(Petr_ @ Mar 15 2016, 23:54) *
Я посмотрел исходники. Это имнно так - флаг убирается для новых пакетов (согласно дефолтным установкам)

Где именно он убирается?
Petr_
Цитата(aaarrr @ Mar 15 2016, 21:09) *
Где именно он убирается?


Возможно Вы и правы. Я не нашел снова этого места.
Но наблюдения за сетью не оставляют вариантов!
Стек действительно ждет ACK после второго пакета в моем примере и
только после этого вызывает снова sent.

Если написать так:
Код
tcp_write(pcb, DirLLine, WrPntr, 0); //"нормальный" вариант

Скорость на малых пакетах около 300 Б/сек и ожидание ACK
на каждом пакете от Форточек по 0.3 сек.

Если написать так:
Код
pcb->flags |= TF_NODELAY;
tcp_write(pcb, DirLLine, WrPntr, 0);

Скорость на малых пакетах около 600 Б/сек и ожидание ACK
на каждом втором пакете от Форточек по 0.3 сек.

Если же написать так:
Код
pcb->flags |= TF_NODELAY;
tcp_write(pcb, DirLLine1, WrPntr1, 0);
tcp_output(pcb);
tcp_write(pcb, DirLLine2, WrPntr2, 0);
То имеем ACK на каждую пару пакетов мгновенно и вызывается
sent строго после получения ACK на вручную сформированное "окно".
Скорость 500-700 кБ/сек (в тысячу раз выше!)
на тех же самых малых пакетах.

Так что проблема видна четко и явно.
Решение как то мне не нравится. Хотя видимо хорошо, что есть и такое.
Обновление стека не было с 12-го года...
alag57
Цитата(Petr_ @ Mar 16 2016, 12:57) *
Обновление стека не было с 12-го года...

git clone git://git.savannah.nongnu.org/lwip.git

Из changelog:
Цитата
HISTORY
(git master)
* [Enter new changes just after this line - do not remove this line]
++ New features:
2016-02-22: Ivan Delamer:
* Initial 6LoWPAN support
2015-12-26: Martin Hentschel and Dirk Ziegelmeier
* Rewrite SNMP agent
2015-11-12: Dirk Ziegelmeier
* Decouple SNMP stack from lwIP core and move stack to apps/ directory.
Breaking change: Users have to call snmp_init() now!

ну и т.д.
AleksBak
Цитата(Petr_ @ Mar 16 2016, 11:57) *
...
Так что проблема видна четко и явно.
Решение как то мне не нравится. Хотя видимо хорошо, что есть и такое.
Обновление стека не было с 12-го года...

А здесь есть как отключать этот алгоритм Нейгла - вызовом функций:
Код
tcp_nagle_enable ( struct tcp_pcb * aPcb ); // enable the nagle algorithm

tcp_nagle_disable ( struct tcp_pcb * aPcb ); // disable the nagle algorithm

tcp_nagle_disabled ( struct tcp_pcb * aPcb ); // return true if the algorithm is not enabled

посмотрите там. Вроде там тоже самое, что Вы и делали и делается. Похоже на самом деле, что-то продолжается в этом lwip исправляться и пр. Я склонировал себе и надо бы сравнить как-нибудь. Похоже, что реально бардак, иначе не скажешь, с доками и сайтами у этого lwip. Есть wiki и вроде официальная, а там последняя версия 1.3.0 (?) Ссылка на один сайт (похоже ихний шведский какой-то) вообще уже не работает. sm.gif) Бесплатный сыр он такой. Еще нашел пару ссылок про упоминание lwip + Nagle (можете тоже сами найти если нужно, но там ничего такого).
scifi
Цитата(AleksBak @ Mar 16 2016, 21:01) *
Похоже, что реально бардак, иначе не скажешь, с доками и сайтами у этого lwip. Есть wiki и вроде официальная, а там последняя версия 1.3.0 (?) Ссылка на один сайт (похоже ихний шведский какой-то) вообще уже не работает. sm.gif) Бесплатный сыр он такой.

Там с самого начала так. Ну да, бесплатный сыр. Хороший код, но там реально нужно самому врубиться. Наскоком не получится.
Petr_
Цитата(alag57 @ Mar 16 2016, 14:14) *
git clone git://git.savannah.nongnu.org/lwip.git


Да, спасибо за ссылку. Я это видел.
Насколько я читал - эта фишка есть и в этом моде.
У меня сейчас версия 1.3.1
Но однозначно потом попробую.
AleksBak
Вот, вчера это пропустил - еще там есть по этой теме: Maximizing throughput. Для обоих видов протокола TCP и UDP приводят рекомендации.

Цитата(Petr_ @ Mar 17 2016, 10:56) *
...
У меня сейчас версия 1.3.1
...

А в этой версии есть эти функции: tcp_nagle_enable/tcp_nagle_disable ? Если взять сгенерированное от Куба, то там 1.4.1 (и функции эти есть и еще кое-какие дефайны по этой теме), но правда полученный код уже будет привязан к HAL от Куба. Хотя при желании его (этот HAL) не трудно переписать/убрать на свой.
Petr_
Цитата(AleksBak @ Mar 17 2016, 07:13) *
Вот, вчера это пропустил - еще там есть по этой теме: Maximizing throughput. Для обоих видов протокола TCP и UDP приводят рекомендации.


А в этой версии есть эти функции: tcp_nagle_enable/tcp_nagle_disable ? Если взять сгенерированное от Куба, то там 1.4.1 (и функции эти есть и еще кое-какие дефайны по этой теме), но правда полученный код уже будет привязан к HAL от Куба. Хотя при желании его (этот HAL) не трудно переписать/убрать на свой.


Спасибо за ссылку!!!
Там оказался прямой ответ/совет:
"Try to prevent sending small chunks of data waiting for an ACK: delayed ACK on the remote host might destroy performance (often, only every 2nd packet is ACKed)"
Также совет чуть выше:
"If you write small chunks turn off the nagle algorithm (see wikipedia for more info!) to let the stack send data right away instead of waiting for more data to form bigger packets (see tcp_nagle_disable())."

Иными словами найденный мной вариант и есть лучшее решение - нейгл отключается и шлется 2 "неполных" пакета немедленно. И именно пара пакетов подтверждается ACK.

В WEB сервере от ST эта проблема замаскирована и не вылезает:D
Там если файл больше пары пакетов (т.е. целого буфера) - буфер заполняется полностью и LwIP шлет 2 пакета добровольно.
А если остаток файла маленький - он шлется и соединение тут же закрывается. Что естественным образом снимает вопрос ожидания ACK на одиночный пакет.

Кстати у меня исходники не от Куба!
Оригинальный пример от ST и заменен HAL путем замены 2-х файлов.
Переделку делал один мой приятель из Штатов.

Версии LwIP пока пробовать не буду, пока не допилю проект.
И опыта поднаберусь и железо получше выучу.
AleksBak
Цитата(Petr_ @ Mar 17 2016, 15:04) *
Спасибо за ссылку!!!
...

Очень рад этому. Реально. beer.gif Но еще вопрос у меня если можно - см. ниже. (Вообще взаимное обсуждение на форуме завсегда полезно я как твердо понял всем - столько мелких моментов всплывает.).
Цитата(Petr_ @ Mar 17 2016, 15:04) *
...
В WEB сервере от ST эта проблема замаскирована и не вылезает:D
Там если файл больше пары пакетов (т.е. целого буфера) - буфер заполняется полностью и LwIP шлет 2 пакета добровольно.
А если остаток файла маленький - он шлется и соединение тут же закрывается. Что естественным образом снимает вопрос ожидания ACK на одиночный пакет.
...

Вы какие исходники WEB сервера от ST смотрели? Даже скажем так - я как понял у ST лучше смотреть там где самое "современное" и иными словами там где самая последняя на данный момент линейка процессоров - M7. Т.е. например от платы DISCOVERY-746 (или EVAL-756). Между прочим там используется ОС т.е. судя по-всему Вы их не смотрели. А вообще Вы хотя и начали со "сложного" пути - без Куба (на самом деле это как обычно и по "старинке"), но все-таки более правильный путь это иногда т.к. вот сейчас например я думаю как бы избавиться полностью от этой cmsis_os.h например (это обертки над "чистыми" функциями FreeRTOS и хоть есть в них некоторые полезности, но лишние они) и еще некоторые вещи. А все потому что стал кушать огромный бесплатный сыр от Куба, объелся/подавился им и самое плохое, что приобрел "наркозависимость" от него (не избавиться от него вот так вот просто). sm.gif
Petr_
Цитата(AleksBak @ Mar 17 2016, 11:33) *
Вы какие исходники WEB сервера от ST смотрели? Даже скажем так - я как понял у ST лучше смотреть там где самое "современное" и иными словами там где самая последняя на данный момент линейка процессоров - M7. Т.е. например от платы DISCOVERY-746 (или EVAL-756). Между прочим там используется ОС т.е. судя по-всему Вы их не смотрели. А вообще Вы хотя и начали со "сложного" пути - без Куба (на самом деле это как обычно и по "старинке"), но все-таки более правильный путь это иногда т.к. вот сейчас например я думаю как бы избавиться полностью от этой cmsis_os.h например (это обертки над "чистыми" функциями FreeRTOS и хоть есть в них некоторые полезности, но лишние они) и еще некоторые вещи. А все потому что стал кушать огромный бесплатный сыр от Куба, объелся/подавился им и самое плохое, что приобрел "наркозависимость" от него (не избавиться от него вот так вот просто). sm.gif


Я взял исходники от их отладочной платы STM3210C-EVAL
Вот отсюда:
http://www2.st.com/content/st_com/en/produ...3210c-eval.html
Далее заменил 2 файла (HAL для Ethernet микросхемы)
поскольку плата у меня Olimex!!
Там все по другому подключено и нет такого красивого ЖКИ :D
WEB сервер и стек сразу заработали.
Никакой "оси" там нет, чему я очень рад. Поскольку не считаю полезным.
Софт от 2009 года и LwIP там 1.3.1


Далее я выпилил поддержку ЖКИ и привел в порядок использование ног.
Ну и теперь пилю сетевую часть проекта.

Petr_
Решил свои проблемы с LwIP и делюсь результатом(может кому надо будет).

Итак проблема долгого ожидания ACK после отправки одиночного малого (меньше TCP_WND)
фрейма есть у всех версий LwIP.
В версии 1.3.1 (с нее начинал) это решается:
Код
pcb->flags |= TF_NODELAY;
tcp_write(pcb, DirLLine1, WrPntr1, 0);
tcp_output(pcb);
tcp_write(pcb, DirLLine2, WrPntr2, 0);

Т.е. формированием окна из 2-х пакетов вручную.
Разумеется pcb->flags |= TF_NODELAY; можно выполнить при открытии
pcb (например из tcp_connect(FC->DATA_pcb, &Rem_Addr, FC->FTPDataPort.Val, DATA_PUTconnected); обработчика)
получив pcb текущего соединения.

В версии 1.4.1 (на нее перешел по указанным ниже причинам) проблема таже
и решение то же. Но есть тонкость:
Код
tcp_nagle_disable(pcb); //(этого нет в 1.3.1)
tcp_write(pcb, DirLLine1, WrPntr1, 0);
tcp_output(pcb);
tcp_write(pcb, DirLLine2, WrPntr2, 0);

Но tcp_output(pcb); не выполняется пока не закомментите вот это из самой tcp_output:
Код
  /* First, check if we are invoked by the TCP input processing
     code. If so, we do not output anything. Instead, we rely on the
     input processing code to call us when input processing is done
     with. */
//  if (tcp_input_pcb == pcb) {
//    return ERR_OK;
//  }

Ну или напишите:
Код
tcp_input_pcb = NULL;
tcp_output(pcb);

Что одно и тоже по сути.
Далее пары пакетов будут получать ACK мгновенно и скорость возрастет на порядки.

Далее в 1.3.1 заметил еще проблему.
При открытии соединения для получения данных ACK при открытии
при получении очередного фрейма LwIP не формирует, пока не вызовете
tcp_write(pcb, "A", 1, 1); Т.е. с чем угодно.
В 1.4.1 этой проблемы нет!
Это и стало причиной перехода с 1.3.1 на 1.4.1

Но помните, что если обрабатываете данные "долго",
вызывайте tcp_recved(pcb, p->tot_len);
в конце, а не начале функции (как сделано в примерах).
Поскольку при ее вызове уйдет ACK и вторая сторона вышлет очередной
пакет. И его можно будет пропустить.
При вызове в конце проблем не возникнет - будет вполне естественное ожидание.
AleksBak
Спасибо большое, что отписались! Я вот тоже немного почитал/посмотрел по теме этого LwIP и оказывается веб-сервер у него есть свой. И файловая система в нем своя. А STM получается, просто переделала этот готовый веб-сервер под себя. Так получается сколько не смотрю. Нашел LwIP-овские исходники с примерами для веб-сервера и еще некоторых вещей (в общем наз. lwip-contrib) скачал/посмотрел - там есть примеры портирований под linux/win.
Petr_
Цитата(AleksBak @ Mar 22 2016, 15:55) *
Спасибо большое, что отписались! Я вот тоже немного почитал/посмотрел по теме этого LwIP и оказывается веб-сервер у него есть свой. И файловая система в нем своя. А STM получается, просто переделала этот готовый веб-сервер под себя. Так получается сколько не смотрю. Нашел LwIP-овские исходники с примерами для веб-сервера и еще некоторых вещей (в общем наз. lwip-contrib) скачал/посмотрел - там есть примеры портирований под linux/win.


Я Вам там вопрос написал в личку на микрочипе.
Там по pcb и их разделению.
Если не дойдет - тут повторю.

А WEB сервер то довольно очевидный...
Я именно работу с ~~ прилаживаю.
Чтоб было проще чем у микрочипа и быстро.
Ну и у меня часть страницы по замыслу во флеше лежит,
а часть на SD карте. С этим тоже определенная работа есть.
Кроме того есть плотная связь с SVG модулями для браузера.
Тут еще головняк.
Но более менее получается.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.