Подтвердить что ты не робот

Открытие службы Wifi P2P работает с перерывами

Обнаружение службы Wifi P2P не ведет себя так, как ожидалось. Я вижу прерывистые проблемы, когда слушатели DNSSD не вызываются всегда, и, следовательно, у меня нет подсказки о соседних устройствах, работающих с одним и тем же приложением. Я использую следующие два API: один для регистрации службы, которая будет открыта другими устройствами, а другая для обнаружения соседних служб, работающих на других устройствах. Любая идея, если я делаю что-то неправильно здесь или есть определенная последовательность других вызовов API андроида, которые должны быть сделаны до того, как я вызову эти 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);
4b9b3361

Ответ 1

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), вы должны использовать метод WifiP2pManager clearLocalServices. И важно, чтобы вы < только вызывали addLocalService, если слушатель прошел в clearLocalServices, возвращенном с обратным вызовом onSuccess.

Хотя это очень хорошо настраивает трансляцию, я обнаружил, что другие узлы не всегда могли обнаружить широковещательный Service (особенно, когда эти узлы уже не активно обнаруживали службы в момент регистрации локального Service - но они "присоединились" позже). Я не мог найти способ исправить эту проблему на 100% надежно. И поверьте мне, я пытался, вероятно, все WifiP2p -релизировать. И нет, последовательность clearLocalServices - addLocalService не давала удовлетворительных результатов. Или более того: что-то другое работало намного лучше. То, что я решил сделать, было после того, как я успешно добавил локальную службу (onSuccess обратный вызов из addLocalService), я запустил Thread, который периодически вызывал метод WifiP2pManager discoverPeers. Это, казалось, заставляло ретранслировать всю информацию 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 выполнялось с помощью интуитивного метода (просто повторяя указанную последовательность: removeServiceRequestaddServiceRequestdiscoverServices).

База моего кода выглядела более-менее подобной (для запуска 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
                }
            });
}

mServiceDiscoveringRunnable был просто:

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

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

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

Ответ 2

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