Как избежать потери пакетов при ретрансляции TCP пакетов из быстрого интерфейса в медленный?
Проблема:
При передачи данных через канал связи, включающий в себя ретранслятор пакетов из быстрого интерфейса в медленный, теряются пакеты. Протокол TCP производит повторную отправку этих пакетов, но скорость передачи падает.
Передача в обратную сторону происходит без ошибок.
Канал связи:
[ PC, Windows ]------EthOverUSB------>[ STM32, LWIP ]-------PPPoS------->[ ARM, Linux ]
EthOverUSB - FullSpeed USB (12 Mbit/s)
PPPoS - RS422 (921600 bit/s)
Детали:
Протокол TCP производит повторную отправку потерянных пакетов, при этом падает скорость на ~5%. При этом на стороне приемника (Linux) фиксируется 3.7% битых пакетов.
Причины:
Отправитель шлет пакеты в быстрый интерфейс (USB), но медленный (PPP) не успевает передавать пакеты с такой скоростью и они копятся в буфере на ретрансляторе (STM32). При переполнении этого буфера и теряется пакет.
Пути решения:
1. Первое, что приходит в голову - понизить скорость USB, но в STM32 LowSpeedUSB (1.5 Mbit/s) не поддерживается, а другой способ ограничить скорость я не нашел. Может быть он есть?
2. Как-то настроить параметр Window Size протокола TCP. Но как? и где?
3. ???
Мне кажется, что эта проблема должна как-то нормально решаться. Но пока найти это решение не могу.
Буду благодарен за помощь.
Wexter, Я не могу контролировать отправку пакетов. Скорость отправки как-то высчитывается из скорости установленного соединения и, по идее, времени ответа на TCP пакеты.
В том и вопрос, как использовать не всю пропускную способность USB или ее понизить?
Андрей Лавровский, в вашем случае если только расширять исходящий канал.
Все хосты со стороны более быстрого будут в любом случае утилизировать всю доступную пропускную способность.
У вас в любом случае будут дропы пакетов в сторону перегруженного медленного и это абсолютно нормальная ситуация в сетях. И решается она либо ограничением трафика со стороны хостов, либо расширением канала
Механизм ограничения скорости в tcp как раз и построен на потере пакетов.
Опишите проблему более развернуто.
Разными манипуляциями можно снизить скорость, первое что приходит в голову, если медленный usb не поддерживается, сделать прослойку виртуальных сетевых интерфейсов на win машине, а в них явно задать скорость, это можно сделать даже на физических интерфейсах, в простейшем случае нужно две сетевые карты. Но это не решит проблему, а только перенесет ее в другое место.
Если у вас есть девайс или софт отправляющий данные, то именно он должен разруливать скорость иначе в любом случае будут потери пакетов. Проще говоря, чтобы пакеты не терялись или их нужно медленно отправлять или копить в буфере, но метод с буфером работает только если скорость отправки гуляет, если она всегда выше скорости передачи, то любой буфер рано или поздно закончится.
Что у вас является источником данных?
nApoBo3, Задача состоит в том, чтобы можно было подключиться по SSH к Linux машине из любой программы типа Putty, WinSCP... Еще должна грузиться веб-страница устройства через это соединение.
Вообще после подключения USB к Windows образуется сетевое соединение, а дальше с ним можно делать все, что угодно.
Судя по описанию, размер окна TCP должен это решать. Но пока не получил какой-либо положительный результат.
Можете ниже посмотреть, что по этому поводу писали, там и проблема описана подробнее.
Я пробовал подменять размер окна на STM, но это вызвало еще больше ошибок. Размер окна должен задавать Linux.
Надо попробовать ограничивать размер окна на Линуксе. Но он поддерживает несколько интерфейсов, поэтому могут быть проблемы с другими.
Андрей Лавровский, это параметр, который посылаешь удаленной системе, при создании тцп канала. какие ошибки возможны не понятно.
никто не запрещает тебе на ретрансляторе при создании тцп-канала с быстрым источником прописать небольшое окно.
еще посмотри в твоем стеке, как можно вручную управлять отсылкой подтверждения о приеме пакетов.
pfg21, Так ведь размер окна может меняться в процессе передачи и отправляется в каждом пакете.
Я менял его на ретрансляторе в каждом пакете в обе стороны и вот, что получилось:
Сначала идет 1 подтверждение на 1 пакет, потом ТРС разгоняется и отправляет подтверждения на каждый второй пакет. До этого момента все работает хорошо (как и ожидалось). Потом подтверждение начинает отправляться на каждый третий пакет, а физический размер окна позволяет отправить только два.
В итоге получается очень долгий простой и итоговая скорость очень маленькая.
Андрей Лавровский, мне кажется ты путаешь с длиной пакета MTU ?? это немного другое :)
размер окна приема описывает размер RX буфера в драйвере TCP/IP. он гораздо больше пакета.
пардон, не сильно помню тцп стек, мне мне видится такой вариант: на ретрансляторе отлавливать подтверждения пакетов, идущие в быстрое соединение, и притормаживать их при наполнении буфера смотрящего в сторону медленного соединения.
источник не сможет заслать новые пакеты (свыше окна приема, его тоже сделать небольшим) пока не получит подтверждения отправленных. и буфер на ретрансляторе не переполнится.
тцп стек увеличивает окно приема по мере работы канала. это увеличивает скорость.
многие (и я в том числе) ускоряют тцп канал отключением "мягкого" старта т.е. начальный размер окна прописывается в системе очень большим.
pfg21, MTU и размер окна не путаю, пробовал менять именно размер окна.
Да, нужно что-то делать с размером окна. Буду думать в этом направлении.
Но простая подмена, как я описал выше, не дала положительного результата.
Получатель отправляет подтверждение, в котором указывает размер окна 32000 (например), на ретрансляторе это значение подменяется на количество свободных байт - 4000.
После этого отправитель знает, что может отправить 2 пакета по 1500 байт.
НО! Получатель думает, что ему могут отправить 32000 байт.
В ТСР подтверждения шлются сначала на каждый пакет, потом на каждый второй, потом на каждый третий итд, если не возникает никаких проблем.
Получается, что отправитель может отправить только два пакета из-за размера окна, а получатель ждет третий пакет, чтобы отправить подтверждение. Но его нет и все подвисает до какого-то таймаута.
Может быть нужно ограничить размер окна у получателя.
А без каких-то изменений получается так. Размер окна сначала растет от нуля, а потом всегда приходит ~3000 и не меняется. Потому что получатель значительно быстрее обрабатывает байты, чем они приходят по медленному каналу и буфер всегда свободен на момент отправки подтверждения.
График окна для MTU 900 байт.
Здесь зеленая линия - размер окна, он не меняется.
А с синей странности. Отправляется по два пакета, приходит подтверждение. Так несколько раз происходит. Потом почему-то отправляется не 2, а 3 пакета, затем поднимаемся на следующую ступеньку.
Почему он отправляет иногда по три пакета?
А как значение MTU связано с общей пропускной способностью?
Сейчас оно 1500, если уменьшить, то будет та же проблема, но через большее количество маленьких пакетов.
Андрей Лавровский, еще сильнее надо уменьшить. до 750 например. пакеты, само собой, меньше, и скорость будет меньше, зато потери должны уменьшиться. вообще это должно автоматом отрабатывать при потерях.
SysAn, Автоматом должен меняться MTU?
Могу попробовать, но буфер на STM все равно переполнится через какое-то количество пакетов. И потери уменьшатся, но все равно будут.
В обратную сторону работает без единой ошибки, с равномерной скоростью и все такое. Кажется, что как-то должно быть можно сделать аналогичное качество канала и в прямом направлении.
да, MTU - это максимальный размер. при плохом прохождении он должен уменьшаться. это чистая физика, маленькие пакеты лучше ходят на нестабильных участках.
SysAn, с 750 проблема остается.
В WireShark-е есть график количества байтов, отправленных в сеть, но еще не подтвержденных. Этот график представляет собой лесенку в моем случае. При уменьшении MTU изменяется высота ступенек и их количество. А после переполнение, ретрансмитт и все заново.
Андрей Лавровский, MTU это второй уровень.Он не поможет. Нужно MSS ограничить. MSS относится уже к 4 уровню.
и у TCP есть особенность что он разгоняется при передаче. Если я правильно помню, как раз значение MSS постепенно растет, из-за этого payload потихоньку увеличивается, пока не выйдет на максимальную скорость.
В любом случае скорее всего решение лежит в рамках тюнинга TCP стека.
DDwrt100, максимальный размер MSS = MTU − размер заголовка IP − размер заголовка TCP.
То есть, ограничивая MTU, я ограничивал и MSS. При этом длина всех пакетов при передаче равнялась этому максимальному MSS.
аким образом, если ваши два офиса соединяет канал связи в 10 Мбит/сек и круговое время составляет 85 миллисекунд, то воспользовавшись данной формулой, мы получим значение окна равное:
10 000 000 * 0,085 / 8 = 106250 байт
Размер поля Window в заголовке TCP составляет 16 бит; это означает, что узел TCP может указать максимальный размер TCP окна 65535 байт. Таким образом, максимальная пропускная способность составляет:
65535 * 8 / 0,085 = 6,2 Мбит/сек