Java - ненадежность Android UDP

У меня экстремальные потери пакетов UDP с Android, и это не имеет смысла. Ситуация следующая:

  1. ПК с Java-клиентом, подключенным к домашней сети
  2. Телефон с Java-сервером (Android), подключенным к домашней сети
  3. Домашний роутер — новый WRT1900ac. Сеть имеет выход в интернет.
  4. Пакеты UDP маленькие (‹ 15 байт)

Симптомы:

  1. Если ПК отправляет пакет UDP на другой ПК (оба в одной сети), он работает очень хорошо (пакеты почти не теряются).

  2. Если Android отправляет пакет UDP на ПК в той же сети, он также работает очень хорошо (пакеты почти не теряются).

  3. Если ПК отправляет UDP на Android в той же сети, я получаю большие потери пакетов (50% времени или более, но это бывает по-разному).

В большинстве случаев я вынужден отправить пакет около 10 раз, чтобы пройти один. В остальное время все проходит с довольно большой задержкой. Очень странное поведение, которое происходит только на принимающей стороне Android. Если я заменю android на компьютер с тем же кодом на java или просто получу пакет через UDP-сервер Packet Sender, у меня не будет проблем с потерей. Еще одна вещь, которую я заметил, заключается в том, что если вместо использования маршрутизатора я использую другую точку доступа, которая не имеет подключения к Интернету или других клиентов, производительность резко улучшается. Это ожидаемо, но мой вопрос заключается в том, почему принимающая сторона Android наблюдает такую ​​плохую производительность и теряет так много пакетов. Когда Android заменяется другим ПК с тем же кодом и в той же сети, проблем не возникает. Android также не имеет проблем с отправкой пакетов (пакеты не теряются). Следовательно, это должно быть что-то еще, связанное с Android на принимающей стороне...

Я также попытался заменить код ПК на Packet Sender и получил те же результаты. Проблема, похоже, в принимающей стороне Android. Я запускаю один и тот же код UDP на стороне ПК и на Android.

Код отправки UDP прост:

public void sendMessage(String message)
{
    try {
        DatagramSocket ds = new DatagramSocket();
        DatagramPacket dp;
        InetAddress local = InetAddress.getByName(ipPool);
        dp = new DatagramPacket(message.getBytes(), message.length(), local, port);
        ds.setBroadcast(true);
        ds.send(dp);
        ds.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Код получения UDP на Android находится в классе сервера UDP:

public class UDP_Server
{
    CommandParser commandParser;

    public UDP_Server(MainActivity mainActivity)
    {
        Log.i("Udp tutorial", "---------------------------Starting UDP SERVER");

        commandParser = new CommandParser(mainActivity);
        String text;
        int server_port = 9876;
        try
        {
            DatagramSocket s = new DatagramSocket(server_port);
            s.setBroadcast(true);
            //s.setReceiveBufferSize(163840);


            while (true)
            {
                byte[] message = new byte[1024];
                DatagramPacket p = new DatagramPacket(message, message.length);

                s.receive(p);
                text = new String(message, 0, p.getLength());
                Log.d("Udp tutorial","message:" + text);
                //commandParser.parseCommand(text);
                //s.close();
            }
        } catch (SocketException e)
        {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

Класс UDPServer.java создается с помощью метода основного действия onCreate():

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
        StrictMode.setThreadPolicy(policy);

        wm = (WifiManager) getSystemService(WIFI_SERVICE);

        Log.i("Udp tutorial", "---------------------------HERE 1");
        Thread thread = new Thread(new Runnable()
        {
            public void run()
            {
                UDP_Server svr = new UDP_Server(MainActivity.this);
            }
        });

        thread.setPriority(Thread.MAX_PRIORITY);
        thread.start();
//        TCPServer server = new TCPServer();
    }

person Enk73a    schedule 19.12.2016    source источник
comment
Не уверен, что это то, что можно решить таким образом ... меня не удивит, если вам придется использовать какой-то инструмент, такой как wireshark или что-то в этом роде, чтобы внимательно наблюдать за всем сетевым трафиком, чтобы понять, что происходит.   -  person GhostCat    schedule 19.12.2016
comment
Как сказано выше, попробуйте использовать wireshark и посмотрите, что происходит. Кроме того, попробуйте другое устройство Android, если возможно, чтобы увидеть, есть ли проблема с вашим устройством.   -  person jython234    schedule 22.12.2016


Ответы (1)


У меня были катастрофические результаты с некоторыми устройствами Android, отправляющими файл на сервер TFTP (на основе UDP) через WiFi, но, похоже, это работало хорошо с другими устройствами Android.

Блоки данных (от устройства к серверу) были отправлены правильно, но блоки подтверждения (от сервера к устройству), казалось, были потеряны в подвешенном состоянии.

Оказывается, мне пришлось приобрести многоадресную блокировку, чтобы эти неисправные устройства работали должным образом (спасибо https://www.b4x.com/android/forum/threads/enable-multicast.43321/#post-263242).)

WifiManager wifi = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
WifiManager.MulticastLock multicastLock = wifi.createMulticastLock("multicastLock");
multicastLock.setReferenceCounted(true);
multicastLock.acquire();

...

multicastLock.release();

Надеюсь это поможет.

person Clément Mangin    schedule 04.07.2017