web-dev-qa-db-ja.com

WifiP2Pサービスディスカバリは断続的に機能します

WifiP2Pサービス検出が期待どおりに動作していません。 DNSSDリスナーが常に呼び出されるとは限らないため、同じアプリを実行している近くのデバイスの手がかりがないという断続的な問題が発生しています。私は次の2つのAPIを使用しています。1つは他のデバイスによって検出されるサービスを登録するためのもので、もう1つは他のデバイスで実行されている近くのサービスを検出するためのものです。ここで何か間違ったことをしているのか、他のAndroid 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);
30
Soumya Das

WifiP2p(一般的に):

少し前に、私はWifiP2pService Broadcasting/Discoveryに基づいた非常に複雑なネットワーク接続システムを備えたアプリケーションを開発していました。そして、その経験に基づいて、私はすでにここにいくつかの投稿を書いていますSOそれがどれほど難しいか、身に着けているか、問題があるかについて。ここに2つあります(それらは私が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メソッドで)登録する前に、WifiP2pManagerclearLocalServicesメソッドを使用する必要があります。また、リスナーがaddLocalServiceコールバックで返されたclearLocalServicesを渡した場合は、onlyonSuccessを呼び出す必要があることが重要です。

これによりブロードキャストは非常にうまく設定されますが、他のノードがブロードキャストされたserviceを常に検出できるとは限らないことがわかりました(特に、ローカルServiceの登録時にこれらのノードがサービスをアクティブに検出していなかった場合は、後で「参加」しました) )。この問題を100%確実に修正する方法を見つけることができませんでした。そして、私がおそらくWifiP2p関連のすべてを試していたと信じてください。いいえ、clearLocalServices-addLocalServiceシーケンスは、実際には満足のいく結果をもたらしていませんでした。またはそれ以上に:何か違うことをすることははるかにうまくいった。私がやろうと決めたのは、正常にローカルサービスを追加した後(onSuccessからのaddLocalServiceコールバック)、定期的にWifiP2pManagerのメソッドThreadを呼び出す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の「再検出」を強制しようとすることの両方。

セットアップは、次の3つのWifiP2pManagerのメソッドのシーケンスで実行されました。

removeServiceRequestaddServiceRequestdiscoverServices

それらはこの正確な順序で呼び出され、特定のメソッド(正確には2番目または3番目のメソッド)は、前のメソッドが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
                }
            });
}

mServiceDiscoveringRunnableは次のとおりです。

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

これらすべてが私のシステムを非常にうまく機能させました。まだ完璧ではありませんでしたが、このテーマに関するドキュメントが不足しているため、これ以上改善することはできなかったと思います。

このアプローチをテストする場合は、それがどのように機能するかを必ず教えてください(またはifそれがあなたのために機能する;))。

29
Bartek Lipinski

問題がサービスの検出である場合、デバイスとサービスを検出可能にするための最善の方法はクレアリンググループであると思いますが、すべてのデバイスでグループが作成されている場合は、直接接続できません。しかし、wifiネットワークとして。私は毎日それをします、そしてそれは働きます。

0
NDev