Серьезная потеря пакетов UDP на некоторых устройствах Android

я прочесал interwebz без результата. Мы сталкиваемся с проблемой, когда некоторые устройства Android испытывают серьезную потерю пакетов. Чтобы дать некоторый фон, приложение подключается к определенному Wifi и ищет UDP-пакеты, транслируемые на порт 17216. Эти пакеты имеют размер 832 байта, исключая обернутые заголовки, и отправляются с регулярной скоростью четыре в секунду.

мы столкнулись с проблемой только на двух устройствах, планшете Turbox Rubik II и планшете ASUS Memo Pad HD 7. Другие устройства, которые мы тестировали (телефоны и планшеты), собирают пакеты с установленным регулярным интервалом.

функция, которая получает пакеты, такова:

public void run()
{
    while (isUDPServerRunning)
    {
        try
        {
            socket.receive(packet);

            ProcessRawPacketData();

            DisplayLoggingInfo();

        }
        catch (IOException e)
        {
            Log.e("receive", e.getMessage());
            e.printStackTrace();
        }
    }
}

и это часть Runnable. Сокет создается таким образом:

byte[] buffer = new byte[1024];

DatagramSocket socket;
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);

при инициализации сокета в onCreate() способ нашего

4 ответов


потеря пакета (как вы знаете, конечно) может произойти на нескольких этапах вдоль передачи:

  1. отправка с сервера
  2. передача по сети
  3. физический прием у клиента и обработка в аппаратном
  4. обработка / буферизация пакета в ядре / ОС
  5. обработки/буферизации пакета в вашем приложении.

вы можете быстро проверить, является ли пункт 1 или 2-Проблема с устройства прослушивают одну и ту же трансляцию при подключении к одному маршрутизатору Wifi. Похоже, вы уже сделали это, и нет никаких проблем. (Обратите внимание, что пакет, который отбрасывается на Шаге 2 (или иногда даже 1), может не отсутствовать в дампе WireShark, если вы запустите его на сервере.)

точки с 3 по 5, поэтому, вероятно, будут проблемой, и их может быть немного сложнее отделить.

вот несколько вещей, которые могут помогите!--1-->

  • как предложил @Mick, не просто распечатайте , когда вы получили пакет, но дайте каждому пакету увеличивающийся идентификационный номер, чтобы выяснить, действительно ли вы потеряли пакет или он был просто задержан.
  • переместите код приема пакетов в свой собственный поток (если это еще не так) и установить приоритет из этой нити в MAX_PRIORITY чтобы свести к минимуму вероятность того, что ваш код является задерживаете обед. Учитывая, что Блокнот является четырехъядерной машиной 1.2 GHz, MAX_PRIORITY даже не должен быть необходим, но если вы в настоящее время не используете цикл приема в своем собственном выделенном потоке, вы можете увидеть ХИК-апы в любом случае. Если это исправляет вещи, просто имейте минимальный цикл приема, вставляйте пакеты в свою собственную буферную очередь и обрабатывайте их независимым потоком.
  • Проверьте / увеличьте размер буфера пакетов для приема пакетов через setReceiveBufferSize(...) (более подробная ссылка на Java здесь). Убедитесь, что вы указали размер, который может содержать много пакетов. Учитывая, что запуск packet-sniffer иногда, кажется, помогает вещам, похоже, что может быть какая-то настройка сокета, которая может улучшить вещи, которые sniffer устанавливает.
  • на сервере вы также можете добавить тег к пакету, который сообщает всем вовлеченным устройствам, как обращаться с пакетом. Если ты позвонишь ... setTrafficClass (IPTOS_RELIABILITY), вы просите всех участников оптимизировать обработку пакетов для максимальной надежности. Не все устройства будут заботиться, но это может иметь значение.
  • вы можете попробовать использовать DatagramChannels вместо DatagramSockets, а затем использовать select () дождаться следующего пакета для чтения. Хотя это технически не должно иметь значения, иногда использование другого вызова API может обеспечить обходной путь для вопрос.
  • к сожалению, Android - это очень гетерогенная среда, в которой многие производители будут предоставлять свои собственные модули ядра и т. д. Это также вводит различные несовместимости или нестандартное поведение повсюду. Возможно, вы сможете найти пользовательский ПЗУ (Cyanogen и т. д.?) для одного или обоих ваших проблемных устройств. Если установка этого вместо заводского ПЗУ исправляет вашу проблему, то это ошибка в сетевых драйверах производителя (ядра), и в этом случае вы можете Вам повезет найти обходной путь, или вы можете подать с ними отчет об ошибке, но в целом вам, возможно, придется выбрать эти устройства как неподдерживаемые в Play Store, чтобы избежать плохих отзывов...

наконец, вот работа, которая должна решить проблему наверняка:

добавьте код к вашему клиенту, который обнаруживает сброшенные пакеты, и, если скорость падения слишком высока, открывает TCP-соединение с сервером, которое затем гарантирует доставку пакетов. С учетом что ваши пакеты малы и нечасты и что только несколько устройств когда-либо понадобится использовать этот механизм, я не думаю, что это должно вызвать проблему для загрузки сервера. Если у вас нет способа изменить код сервера для предоставления потока TCP, вы можете написать независимый прокси-сервер, который собирает UDP-пакеты и делает их доступными через TCP. Если вы можете запустить его на том же компьютере, что и исходный сервер, вы даже знаете, на каком IP-адресе он находится (такой же, как исходный адрес пакеты UDP, которые прибыли).


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

Я знаю, это звучит маловероятно для скорости передачи данных около 4 Кб/с... Но если ваши вычисления занимают больше 250 мс, чем это произойдет рано или поздно. Это также объясняет, почему некоторые устройства работают как шарм, а другие нет.

вы пытались удалить вычисления и просто распечатайте сообщение "пакет получен" для отладки?


интересно, что оба устройства, которые испытывают потерю пакетов UDP, имеют сок Mediatek. Есть ли у других тестовых устройств такой же набор микросхем?

Это может быть ошибка в драйвере для Wi-Fi из этих соц. Будучи тем, что он появляется только с UDP, и не всегда 100%, это может быть незаметно для всех до сих пор.


Это звучит очень похоже на симптомы интерференции Bluetooth, которые можно увидеть на устройствах Android (и iOS - на самом деле все с WiFi и Bluetooth вместе).

2.4 Ghz WiFi и Bluetooth имеют одинаковую пропускную способность и могут мешать друг другу - на некоторых устройствах это выражено, возможно, из-за внутренней компоновки.

также возможно, что вы можете увидеть его на некоторых устройствах, а не на других из-за версий WiFi, которые они поддерживают-более новые 5GHz основанный wifi не мешает bluetooth таким же образом, но некоторые старые или более базовые устройства Android могут не поддерживать это.

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