Обнаружение службы Wi-Fi P2P работает с перебоями

Обнаружение службы Wi-Fi P2P не работает должным образом. Я вижу периодические проблемы, когда прослушиватели DNSSD вызываются не всегда, и поэтому я понятия не имею о ближайших устройствах, на которых запущено одно и то же приложение. Я использую следующие два API: один для регистрации службы, которая будет обнаружена другими устройствами, а другой — для обнаружения ближайших служб, работающих на других устройствах. Любая идея, если я делаю что-то неправильно здесь или есть какая-то конкретная последовательность других вызовов API Android, которые необходимо выполнить, прежде чем я вызову эти API, чтобы гарантировать, что слушатели всегда вызываются всякий раз, когда регистрируется новая служба или даже если служба регистрируется до того, как мы вызовем API для обнаружения локальных служб.

API для регистрации локальной службы:

private void registerService() {
    Map<String, String> values = new HashMap<String, String>();
    values.put("name", "Steve");
    values.put("port", "8080");
    WifiP2pServiceInfo srvcInfo = WifiP2pDnsSdServiceInfo.newInstance(mMyDevice.deviceName, "_http._tcp", values);

    manager.addLocalService(channel, srvcInfo, new WifiP2pManager.ActionListener() {

        @Override
        public void onSuccess() {
            Toast.makeText(WiFiDirectActivity.this, "Local service added successfully", 
                Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onFailure(int reasonCode) {
            Toast.makeText(WiFiDirectActivity.this, "Local service addition failed : " + reasonCode,
                    Toast.LENGTH_SHORT).show();
        }
    });
}

API для обнаружения локальных сервисов:

public void discoverService() {

    manager.clearServiceRequests(channel, null);

    DnsSdTxtRecordListener txtListener = new DnsSdTxtRecordListener() {
        @Override
        /* Callback includes:
         * fullDomain: full domain name: e.g "printer._ipp._tcp.local."
         * record: TXT record data as a map of key/value pairs.
         * device: The device running the advertised service.
         */
        public void onDnsSdTxtRecordAvailable(String fullDomain, Map record, WifiP2pDevice device) {
            Log.d(TAG, "DnsSdTxtRecord available -" + record.toString());
        }
    };

    DnsSdServiceResponseListener servListener = new DnsSdServiceResponseListener() {
        @Override
        public void onDnsSdServiceAvailable(String instanceName, String registrationType, WifiP2pDevice resourceType) {
            Log.d(TAG, "onBonjourServiceAvailable " + instanceName);
        }
    };

    manager.setDnsSdResponseListeners(channel, servListener, txtListener);

    WifiP2pDnsSdServiceRequest serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();
    manager.addServiceRequest(channel, serviceRequest, new ActionListener() {

        @Override
        public void onSuccess() {
            // Success!
            Log.d(TAG, "addServiceRequest success");
        }

        @Override
        public void onFailure(int code) {
            // Command failed.  Check for P2P_UNSUPPORTED, ERROR, or BUSY
            Log.d(TAG, "addServiceRequest failure with code " + code);
        }

    });
    manager.discoverServices(channel, new ActionListener() {

        @Override
        public void onSuccess() {
            // Success!
            Log.d(TAG, "discoverServices success");
        }

        @Override
        public void onFailure(int code) {
            // Command failed.  Check for P2P_UNSUPPORTED, ERROR, or BUSY
            if (code == WifiP2pManager.P2P_UNSUPPORTED) {
                Log.d(TAG, "P2P isn't supported on this device.");
            } else {
                Log.d(TAG, "discoverServices failure");
            }
        }
    });
}

Примечание: менеджер и канал инициализируются как

WifiP2pManager manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
Channel channel = manager.initialize(this, getMainLooper(), null);

person Soumya Das    schedule 10.10.2014    source источник
comment
Я испытываю то же самое, иногда случаются обратные вызовы в DnsSdServiceResponseListener. Вы выяснили причины этого или это не стабильная функция?   -  person user331244    schedule 15.06.2015


Ответы (2)


WifiP2p (в целом):

Некоторое время назад я разрабатывал приложение с довольно сложной системой сетевого подключения на основе WifiP2p с Service Broadcasting/Discovery. И, основываясь на этом опыте, я уже написал здесь на SO несколько постов о том, насколько это сложно, утомительно и проблематично. Вот два из них (они полны внутренних знаний, которые я получил о WifiP2p с Service Discovery и о самом WifiP2p):

Почему обнаружение пиров для Android WifiDirect так ненадежно

Wi-Fi P2P. Информировать всех доступных пиров о некотором событии

Я бы посоветовал вам прочитать оба моих ответа (хотя они немного больше сосредоточены на самом WifiP2p). Они должны дать вам некоторое представление о вещах, которые вы должны искать при работе с WifiP2p Service Discovery. Я могу легко сказать, что если вы хотите построить эффективную, относительно надежную и надежную систему соединения WifiP2p (особенно с Service Discovery), вам придется попотеть.

WifiP2p Service Discovery:

Чтобы лучше ответить на ваш точный вопрос, я расскажу вам, что я сделал (в отличие от вас), чтобы мой Service Discovery работал довольно надежно.

1. Трансляция Service:

Прежде всего: перед регистрацией вашего Service (методом addLocalService) вы должны использовать метод clearLocalServices WifiP2pManager. И важно, чтобы вы только вызывали addLocalService, если прослушиватель передал clearLocalServices, возвращенный с обратным вызовом onSuccess.

Хотя это довольно хорошо настраивает широковещательную рассылку, я обнаружил, что другие узлы не всегда могли обнаружить широковещательный service (особенно когда эти узлы еще не обнаруживали активно службы в момент регистрации вашего локального Service, но они «присоединились» позже). ). Я не мог найти способ решить эту проблему на 100% надежно. И поверьте мне, я пытался, вероятно, все, что связано с WifiP2p. И нет, последовательность clearLocalServices-addLocalService не давала удовлетворительных результатов. Или даже больше: делать что-то другое работало намного лучше. Что я решил сделать, так это то, что после того, как я успешно добавил локальную службу (обратный вызов onSuccess от addLocalService), я запустил Thread, который периодически вызывал бы метод discoverPeers WifiP2pManager. Казалось, это вынуждало ретранслировать всю service информацию.

Итак... в основном код вашего вещания должен выглядеть более-менее так (имейте в виду, что каждый фрагмент кода, который я публикую здесь, лишен всех "проверок", если система сетевого подключения находится в правильном состоянии). государство, вы должны разработать их самостоятельно, чтобы они лучше всего соответствовали вашему решению):

public void startBroadcastingService(){
    mWifiP2pManager.clearLocalServices(mWifiP2pChannel, new WifiP2pManager.ActionListener() {
        @Override
        public void onSuccess() {
            mWifiP2pManager.addLocalService(mWifiP2pChannel, mWifiP2pServiceInfo,
                    new WifiP2pManager.ActionListener() {

                        @Override
                        public void onSuccess() {
                            // service broadcasting started
                            mServiceBroadcastingHandler
                                    .postDelayed(mServiceBroadcastingRunnable,
                                            SERVICE_BROADCASTING_INTERVAL);
                        }

                        @Override
                        public void onFailure(int error) {
                            // react to failure of adding the local service
                        }
                    });
        }

        @Override
        public void onFailure(int error) {
            // react to failure of clearing the local services
        }
    });
}

где должно быть mServiceBroadcastingRunnable:

private Runnable mServiceBroadcastingRunnable = new Runnable() {
    @Override
    public void run() {
        mWifiP2pManager.discoverPeers(mWifiP2pChannel, new WifiP2pManager.ActionListener() {
            @Override
            public void onSuccess() {
            }

            @Override
            public void onFailure(int error) {
            }
        });
        mServiceBroadcastingHandler
                .postDelayed(mServiceBroadcastingRunnable, SERVICE_BROADCASTING_INTERVAL);
    }
};

2. Обнаружение Service:

Для обнаружения вашего service я использовал аналогичный подход. И с подставкой открытия, и с попыткой форсировать "переоткрытие" services.

Настройка производилась последовательностью следующих трех методов WifiP2pManager:

removeServiceRequest, addServiceRequest, discoverServices

Они вызывались именно в таком порядке, и конкретный метод (точнее, второй или третий) вызывался только после того, как предыдущий «возвратился» с обратным вызовом onSuccess.

Повторное открытие services производилось интуитивным методом (просто повторением указанной последовательности: removeServiceRequest -> addServiceRequest -> discoverServices).

База моего кода выглядела более-менее так (для запуска Service Discovery я сначала вызывал prepareServiceDiscovery(), а затем startServiceDiscovery()):

public void prepareServiceDiscovery() {
    mWifiP2pManager.setDnsSdResponseListeners(mWifiP2pChannel,
            new WifiP2pManager.DnsSdServiceResponseListener() {

                @Override
                public void onDnsSdServiceAvailable(String instanceName,
                                                    String registrationType, WifiP2pDevice srcDevice) {
                    // do all the things you need to do with detected service
                }
            }, new WifiP2pManager.DnsSdTxtRecordListener() {

                @Override
                public void onDnsSdTxtRecordAvailable(
                        String fullDomainName, Map<String, String> record,
                        WifiP2pDevice device) {
                    // do all the things you need to do with detailed information about detected service
                }
            });

    mWifiP2pServiceRequest = WifiP2pDnsSdServiceRequest.newInstance();
}

private void startServiceDiscovery() {
    mWifiP2pManager.removeServiceRequest(mWifiP2pChannel, mWifiP2pServiceRequest,
            new WifiP2pManager.ActionListener() {
                @Override
                public void onSuccess() {
                    mWifiP2pManager.addServiceRequest(mWifiP2pChannel, mWifiP2pServiceRequest,
                            new WifiP2pManager.ActionListener() {

                                @Override
                                public void onSuccess() {
                                    mWifiP2pManager.discoverServices(mWifiP2pChannel,
                                            new WifiP2pManager.ActionListener() {

                                                @Override
                                                public void onSuccess() {
                                                    //service discovery started

                                                    mServiceDiscoveringHandler.postDelayed(
                                                            mServiceDiscoveringRunnable,
                                                            SERVICE_DISCOVERING_INTERVAL);
                                                }

                                                @Override
                                                public void onFailure(int error) {
                                                    // react to failure of starting service discovery
                                                }
                                            });
                                }

                                @Override
                                public void onFailure(int error) {
                                    // react to failure of adding service request
                                }
                            });
                }

                @Override
                public void onFailure(int reason) {
                    // react to failure of removing service request
                }
            });
}

the mServiceDiscoveringRunnable was just:

private Runnable mServiceDiscoveringRunnable = new Runnable() {
    @Override
    public void run() {
        startServiceDiscovery();
    }
};

Все это заставило мою систему работать достаточно хорошо. Это еще не было совершенным, но из-за отсутствия документации по этому вопросу я думаю, что не мог сделать больше, чтобы улучшить его.

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

person Bartek Lipinski    schedule 26.07.2015
comment
Я попробовал ваш подход, и он работает лучше, чем документированный учебник Google. Однако я все еще сталкиваюсь с одной проблемой: обнаружение служб может обнаруживать службы, транслируемые другими устройствами, в течение определенного периода времени, затем какое-то время ничего не обнаруживает, а затем процесс повторяется: поиск служб -> ничего -> услуги - › ничего... Как вы думаете? Проблема может быть в железе или в самой системе? - person Richard Wong; 16.09.2015
comment
Трудно сказать, честно... Я помню, что это было не идеально, и иногда пользователям приходилось ждать несколько секунд, чтобы обнаружить другие устройства (сервисы). Я не мог найти решение этой проблемы. Проблема, которую вы описываете, могла происходить и со мной, просто я не видел шаблона (сервисы -> ничего -> сервисы -> ничего...). - person Bartek Lipinski; 18.09.2015
comment
Я обнаружил, что фаза публикации всегда должна предшествовать фазе обнаружения. В противном случае открытие вообще ничего не вернет. - person Roberto Betancourt; 21.10.2015
comment
@RichardWong, я думаю, вы видите, что время ожидания истекло, проверьте эту проблему Android: code.google.com/p/android/issues/detail?id=206123 .. Способ обойти это — принудительно обнаруживать каждые 2 минуты. - person Nonos; 15.06.2016
comment
@BartekLipinski Спасибо за пример кода. Я реализовал что-то подобное, и это работает. Однако это каким-то образом мешает моему телефону подключиться к любой сети Wi-Fi. Вы замечали что-то подобное? - person vipul mittal; 13.12.2016
comment
@vipulmittal Я так не думаю... хотя это было так давно, может с тех пор что-то изменилось. Извините, я не мог помочь. - person Bartek Lipinski; 13.12.2016
comment
@vipulmittal У меня такая же проблема. Вы нашли какое-либо решение до сих пор? - person osayilgan; 24.01.2017
comment
@osayilgan да. Оказывается, вам нужно вызвать stopPeerDiscovery, чтобы Wi-Fi снова заработал. Идеальный способ реализации состоял бы в том, чтобы вызвать discoveryService и DiscoverPeers один раз, а через некоторое время вызвать stopPeerDiscovery и подождать некоторое время повторения. - person vipul mittal; 24.01.2017
comment
@vipulmittal Спасибо за совет. Но я думаю, что у него есть некоторые другие проблемы. Раньше работало, тот же код. Но когда я пытался внедрить ServiceDiscovery рядом с Peer Discovery, он начал вести себя немного странно. Теперь, если я перехожу в раздел Wifi Direct в настройках Wifi, он ищет устройства Wifi Direct, находит некоторые результаты, а затем Wifi перезапускается. Есть идеи ? - person osayilgan; 24.01.2017
comment
@vipulmittal еще кое-что. Я запускаю обнаружение одноранговых узлов, и результат успешно доставлен. Но потом запускаем Service Discovery, который ничего не возвращает Listeners. - person osayilgan; 24.01.2017
comment
@BartekLipinski Не работает. Тестировал разные устройства и использовал точный код, как описано в документации Google. Служба успешно зарегистрирована, но не найдена другим устройством... Я думаю, что инфраструктура Wi-Fi p2p просто полностью сломана, как и инфраструктура Nearby. - person trinity420; 02.05.2017
comment
Что вы используете для своей WifiP2pServiceInfo? Это единственное, что я не вижу здесь определенным - person Code Wiget; 17.04.2020
comment
Это заняло бы у меня целую вечность, чтобы понять! - person Siddharth Kamaria; 10.09.2020

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

person NDev    schedule 28.02.2017