Заказ из 3 позиций уходит, из 80 виснет: ping и Path MTU на Android без root
Ping, traceroute и подбор Path MTU в Android-приложении работают без root и без NDK. Эхо-запросы отправляет ICMP-сокет из android.system.Os или системная утилита /system/bin/ping, traceroute собирается из серии запросов с растущим TTL, а MTU находится подбором размера пакета с запретом фрагментации. Ключи ping зависят от прошивки, поэтому нужен запасной путь.
📦 Заказ из 3 позиций уходит, а из 80 зависает
Торговый агент стоит в магазине на окраине Москвы. Заказ из трёх позиций ушёл в 1С сразу. Заказ из восьмидесяти крутит индикатор, пока не сработает таймаут. Wi-Fi у клиента работает, браузер открывает сайты, мессенджер доставляет сообщения. Поддержка советует перезагрузить планшет, агент перезагружает, картина та же.
Частая причина — MTU. Ethernet пропускает пакет до 1500 байт, а VPN-туннель до офиса забирает часть места под свои заголовки, и по туннелю проходит пакет поменьше. Короткий запрос в него помещается, заказ на восемьдесят позиций нет. Пакет с флагом DF («не фрагментировать») должен вернуть отправителю ICMP-сообщение «требуется фрагментация», и отправитель уменьшит размер. Но межсетевой экран в магазине режет весь ICMP, поэтому сообщение теряется, а пакеты исчезают молча. Такой сбой называют «чёрной дырой» Path MTU.
Ставка простая. Агент диктует заказ менеджеру по телефону, менеджер вбивает его вручную, путает артикулы, отгрузка сдвигается. Каждый такой случай доходит до разработчиков, потому что у поддержки нет ничего, кроме фразы «не отправляется». Разработчик тратит часы на то, что с экрана диагностики видно за минуту. Если приложение обменивается данными с учётной системой, как при интеграции мобильного приложения с 1С, цена таких сбоев растёт вместе с числом устройств в поле.
🧱 «Без root ping не работает»: откуда взялась легенда
Классический ping открывает raw-сокет (SOCK_RAW), а для него нужна привилегия CAP_NET_RAW. У приложений на Android её нет, отсюда и вывод про root. Но ядро Linux умеет ещё «ping-сокеты»: SOCK_DGRAM с протоколом IPPROTO_ICMP. Они доступны без привилегий и умеют только эхо-запросы. Android разрешает их обычным приложениям, их же использует сетевая диагностика в самом AOSP.
Из Java и Kotlin эти сокеты доступны через android.system.Os (API 21 и выше): Os.socket(), Os.setsockoptInt(), Os.sendto(), Os.recvfrom(). NDK для этого не нужен. Он пригодился бы, если писать диагностику на C, но выигрыша это не даёт.
Свой бинарник ping в assets тоже не поможет: приложения с targetSdkVersion 29 и выше не могут запускать файлы из собственного каталога данных. Системный /system/bin/ping лежит вне этого каталога и запускается без проблем.
⚖️ Четыре способа и что каждый умеет
Выбирать приходится между четырьмя вариантами. Они различаются тем, как далеко можно зайти: от «хост жив» до подбора MTU.
| Способ | Время ответа | TTL и traceroute | Запрет фрагментации и MTU | Ограничения |
|---|---|---|---|---|
| InetAddress.isReachable() | нет, только «да» или «нет» | нет | нет | годится для вопроса «сеть вообще есть» |
| TCP-подключение через Socket.connect() | время рукопожатия | нет | нет | проходит там, где ICMP закрыт; показывает доступность сервиса, а не маршрута |
| Утилита /system/bin/ping через ProcessBuilder | да | да, ключом -t | да, где поддержан ключ -M do | текст вывода и набор ключей зависят от прошивки |
| ICMP-сокет через android.system.Os | да | TTL задать можно, адрес промежуточного узла получить сложно | да, через опцию сокета IP_MTU_DISCOVER | больше кода, поведение нужно проверять на каждой прошивке |
Рабочая связка выглядит так: TCP-замер отвечает на вопрос «доступен ли сервер обмена», утилита ping даёт TTL и MTU, ICMP-сокет через Os годится для регулярных замеров задержки, когда разбирать текст не хочется. Если ресурсов хватает на один способ, берите утилиту: она закрывает всё, чего не умеют остальные, ценой парсера.
🛠 Ping через утилиту: запуск и разбор вывода
- ✓Резолвим имя сами через InetAddress.getByName() и передаём в ping готовый IP. Так вы точно знаете, какой адрес проверяется. Весь код живёт вне главного потока, иначе получите NetworkOnMainThreadException.
- ✓Запускаем ProcessBuilder с аргументами -c 4 -W 2 и redirectErrorStream(true), читаем вывод построчно в корутине на Dispatchers.IO.
- ✓Ставим общий таймаут и вызываем destroy(), если процесс завис.
- ✓Из строк вида time=12.3 ms достаём задержки регулярным выражением, из итоговой строки берём число отправленных и полученных пакетов.
- ✓Сырой вывод сохраняем в отчёт целиком. Когда парсер споткнётся на незнакомой прошивке, у поддержки останется текст, который можно прочитать глазами.
На части версий Android для IPv6 вызывают отдельную утилиту ping6, это тоже проверяется при первом запуске.
🧭 Traceroute из серии одиночных ping
Пакет с TTL=1 умирает на первом роутере, и тот присылает ICMP «время жизни истекло». С TTL=2 пакет доходит до второго роутера, и так далее, пока не придёт обычный эхо-ответ от цели. Запускаем ping -c 1 -t N -W 2 для N от 1 до 15–20. В выводе промежуточного узла будет строка вроде «From 10.8.0.1 icmp_seq=1 Time to live exceeded», из неё берём адрес. Строка «bytes from» с адресом цели означает, что маршрут пройден.
Почему не сделать то же на Os-сокете? Адрес роутера, приславшего «время жизни истекло», приходит в служебных данных очереди ошибок сокета, а Os.recvfrom() их не возвращает. Утилита читает очередь сама и печатает адрес в строке «From». Поэтому для traceroute берём процесс.
Звёздочки, то есть хопы без ответа, — норма: многие роутеры молчат на такие запросы. Останавливайтесь после нескольких молчащих хопов подряд. При таймауте в 2 секунды обход 30 хопов занимает до минуты в худшем случае, поэтому показывайте результат по мере поступления. Traceroute показывает, где путь обрывается, но не всегда называет виновный узел.
📏 Path MTU: бинарный поиск по размеру пакета
Размер пакета складывается из данных, 20 байт IP-заголовка и 8 байт ICMP-заголовка. Чтобы проверить полный пакет в 1500 байт, посылаем эхо-запрос с 1472 байтами данных. Для PPPoE с MTU 1492 предел 1464. В IPv6 заголовок занимает 40 байт, так что для 1500 остаётся 1452 байта данных, а минимальный MTU, который обязана пропускать любая IPv6-сеть, — 1280.
- ✓Берём границы размера данных: 548 (для минимального IPv4 MTU 576) и 1472.
- ✓Посылаем ping -c 2 -W 2 -M do -s N, где N — середина диапазона.
- ✓Ответ пришёл: MTU не меньше N+28, поднимаем нижнюю границу. Пришла ошибка «Message too long» или «Frag needed», либо тишина: опускаем верхнюю.
- ✓Повторяем, пока границы не сойдутся. Это около десяти шагов.
Тишина двусмысленна. Это может быть обычная потеря, а может «чёрная дыра» из сценария выше. Поэтому каждый размер проверяем дважды, а неопределённый результат помечаем в отчёте как «нет данных от ICMP». Ключ -M do есть в iputils-версии ping. Если на прошивке его нет, утилита вернёт ошибку разбора аргументов, и приложение переключается на ICMP-сокет через Os с опцией IP_MTU_DISCOVER.
Когда ICMP закрыт полностью, измеряем не MTU, а симптом: отправляем на свой эхо-эндпоинт тела в 500 байт, 1400 байт и 8 КБ и смотрим, на каком размере обмен зависает. Для поддержки этого достаточно, чтобы сказать: проблема в размере пакета, а не в логине или версии приложения.
⚠️ Что ломает диагностику на реальных устройствах
- ✓Операторы связи и корпоративные межсетевые экраны режут ICMP, а HTTPS проходит. Ping молчит при рабочем сервере, поэтому рядом с ним всегда нужна TCP-проверка порта обмена.
- ✓Фоновый запуск по расписанию упирается в Doze и ограничения фоновой работы. Диагностику запускаем по кнопке или автоматически после ошибки обмена, пока приложение на экране.
- ✓Прошивки отличаются ключами ping и форматом вывода. Парсер не должен падать на незнакомой строке, а тестовый парк должен включать устройства каждого производителя, которые реально стоят у заказчика.
- ✓Из разрешений достаточно INTERNET. Отчёт содержит адреса и маршруты, поэтому отправляем его только на собственный сервер компании, а не в сторонние сервисы аналитики.
🤝 Что мы закладываем в B2B-приложение
Диагностику связи мы проектируем как отдельный экран. Кнопка «Проверить связь» запускает TCP-замер до сервера обмена, ping, traceroute и подбор MTU. Результат вместе с версией Android, типом сети и последними строками журнала обмена уходит в поддержку одним сообщением. Менеджер сразу видит, где обрыв: в сети клиента, в VPN или на стороне сервера, и заявка не ходит по цепочке «поддержка — разработчик — сисадмин».
Такой экран нужнее всего в B2B-приложениях с 1С: у торговых агентов, курьеров и кладовщиков сеть меняется несколько раз за смену, а заказ терять нельзя.
Разработка мобильного приложения у нас стартует от 500 000 ₽. Диагностику проще заложить в ТЗ на старте, чем дописывать позже. Если приложение уже в работе, мы смотрим код сетевого слоя и оцениваем доработку отдельно. Подробности по разработке мобильных приложений и ориентиры по ценам и тарифам есть на сайте. Для оценки пригодится короткий бриф: какие устройства в парке, из каких сетей они выходят в интернет и как приложение обращается к 1С.
❓ Частые вопросы
Нужен ли root для ping на Android?
Нет. Эхо-запросы отправляет ICMP-сокет (SOCK_DGRAM с IPPROTO_ICMP) через android.system.Os или системная утилита /system/bin/ping. Root нужен только для raw-сокетов, а ping-сокеты доступны обычному приложению. Из разрешений хватает INTERNET, оно выдаётся при установке. Ни NDK, ни свой бинарник не требуются.
Как сделать traceroute в Android-приложении без NDK?
Запускайте /system/bin/ping с ключом -t и растущим значением TTL от 1 до 15–20. Роутер, где TTL истёк, присылает ICMP-ответ, и утилита печатает его адрес в строке «From». Ответ от самой цели означает конец маршрута. Хопы без ответа показывайте как звёздочки.
Как узнать Path MTU из мобильного приложения?
Бинарным поиском: ping с запретом фрагментации (-M do) и разным размером данных, от 548 до 1472 байт. Самый большой прошедший размер плюс 28 байт заголовков даёт MTU. Каждый размер проверяйте дважды: тишина может быть потерей пакета или заблокированным ICMP.
Почему ping молчит, хотя сайт открывается?
Межсетевые экраны и часть мобильных операторов режут ICMP, а HTTPS при этом проходит. Поэтому рядом с ping нужна TCP-проверка порта вашего сервера: она показывает доступность самого сервиса. Молчание ping без других симптомов неисправностью не считается.
Сколько стоит добавить диагностику связи в мобильное приложение?
Разработка мобильного приложения у нас стартует от 500 000 ₽. Экран диагностики закладываем в ТЗ на этапе проектирования. Для готового приложения оценку делаем после просмотра кода обмена: цена зависит от того, как устроен сетевой слой, поэтому заранее её не называем.
Или позвоните: +7 906 045-28-27 — в рабочее время с 9:00 до 19:00
Остались вопросы? Нужна помощь?
Менеджеры компании с радостью ответят на ваши вопросы, произведут расчет стоимости услуг и подготовят индивидуальное коммерческое предложение.
Бесплатная консультация

