web-dev-qa-db-fra.com

La découverte du service Wifi P2P fonctionne par intermittence

La découverte du service P2P Wifi ne se comporte pas comme prévu. Je vois des problèmes intermittents dans lesquels les auditeurs de DNSSD ne sont pas toujours appelés et par conséquent, je n'ai aucune idée des appareils à proximité exécutant la même application. J'utilise les deux API suivantes: une pour enregistrer un service devant être découvert par d'autres périphériques et l'autre pour découvrir les services à proximité s'exécutant sur d'autres périphériques. Toute idée si je fais quelque chose de mal ici ou existe-t-il une séquence spécifique d'autres appels d'API Android à effectuer avant d'appeler ces API afin de m'assurer que les écouteurs sont toujours appelés chaque fois qu'un nouveau service est enregistré ou même s'il s'agit d'un service est enregistré avant d'appeler l'API pour découvrir les services locaux.

API pour enregistrer un service local:

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 pour découvrir les services locaux:

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");
            }
        }
    });
}

Remarque: le gestionnaire et le canal sont initialisés en tant que

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

WifiP2p (en général):

Il y a quelque temps, je développais une application avec un système de connectivité réseau assez complexe basé sur WifiP2p avec Service Broadcasting/Discovery. Et sur la base de cette expérience, j’ai déjà écrit quelques articles ici sur SO sur la difficulté, l’usure et la problématique. En voici deux (ils regorgent des connaissances que j'ai acquises à propos de WifiP2p avec Service Discovery et WifiP2p lui-même):

Pourquoi la découverte de pairs pour Android WifiDirect est-elle si peu fiable

P2P Wi-Fi. Informer tous les pairs disponibles d'un événement

Je vous conseillerais de lire mes deux réponses (même si elles sont un peu plus centrées sur le WifiP2p lui-même). Ils devraient vous donner une idée des choses que vous devriez rechercher lorsque vous travaillez avec WifiP2p Service Discovery. Je peux facilement dire que si vous voulez construire un système de connexion WifiP2p efficace, relativement fiable et robuste (en particulier avec Service Discovery), vous devrez vous débrouiller.

WifiP2p Service Discovery:

Pour mieux répondre à votre question exacte, je vous dirai ce que j’ai fait (différent de vous) pour que mon Service Discovery fonctionne de manière assez fiable.

1. Broadcasting Service:

Tout d'abord: avant d'enregistrer votre Service (avec la méthode addLocalService), vous devez utiliser la méthode WifiP2pManager's clearLocalServices. Et il est important que vous n'ayez seulement appelez addLocalService si le programme d'écoute a été transmis dans la clearLocalServices renvoyé avec le rappel onSuccess.

Bien que cela règle assez bien la diffusion, j’ai constaté que les autres noeuds n’étaient pas toujours en mesure de détecter la variable service diffusée (en particulier lorsque ces noeuds ne détectaient pas déjà activement les services au moment de l’enregistrement de votre Service locale, mais ils ont "rejoint" plus tard ). Je ne pouvais pas trouver un moyen de résoudre ce problème à 100% de manière fiable. Et croyez-moi, j'essayais probablement tout ce qui était lié au WifiP2p-. Et non, la séquence clearLocalServices-addLocalService ne donnait pas vraiment de résultats satisfaisants. Ou plus encore: faire quelque chose de différent fonctionnait beaucoup mieux. Ce que j’ai décidé de faire, c’est après que j’ai avec succès ajouté le service local (rappel onSuccess de addLocalService), j’ai lancé une Thread qui appellerait périodiquement la méthode WifiP2pManagerdiscoverPeers. Cela semblait obliger à retransmettre toutes les informations service.

Donc ... en gros, la base de votre code de diffusion devrait ressembler moins à ceci (gardez à l'esprit que chaque morceau de code que je vais poster ici est dépouillé de tous les "contrôles" si le système de connectivité réseau est à droite vous devez les concevoir vous-même pour adapter au mieux votre solution):

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
        }
    });
}

où la mServiceBroadcastingRunnable devrait être:

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. Découverte de Service:

Pour la découverte de votre service j'ai utilisé une approche similaire. À la fois avec la mise en place de la découverte, et en essayant de forcer la "redécouverte" de services.

La configuration a été effectuée avec la séquence des trois méthodes WifiP2pManager suivantes:

removeServiceRequest, addServiceRequest, discoverServices

Ils ont été appelés dans cet ordre exact et une méthode particulière (la deuxième ou la troisième pour être exacte) a été appelée uniquement après que la précédente a été "renvoyée" avec le rappel onSuccess

La redécouverte de services a été effectuée avec la méthode intuitive (il suffit de répéter la séquence mentionnée suivante: removeServiceRequest -> addServiceRequest -> discoverServices).

La base de mon code ressemblait de moins en moins à ceci (pour commencer Service Discovery, je commencerais par appeler prepareServiceDiscovery(), puis 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
                }
            });
}

la mServiceDiscoveringRunnable était simplement:

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

Tout cela a fait fonctionner mon système assez bien. Ce n'était pas encore parfait, mais avec le manque de documentation sur ce sujet, je pense que je ne pourrais rien faire de plus pour l'améliorer.

Si vous testez cette approche, assurez-vous de me dire comment cela fonctionne pour vous (ou si cela fonctionne pour vous;)).

27
Bartek Lipinski

si le problème est la détection du service, j’estime que le groupe créatif est le meilleur moyen de rendre l’appareil et le service détectables, mais le groupe s’il est créé dans tous les appareils, vous ne pouvez pas vous connecter en direct. mais en tant que réseau wifi . Je le fais tous les jours et ça marche.

0
NDev