Wifi P2P服务发现间歇性地工作 [英] Wifi P2P service discovery works intermittently

查看:336
本文介绍了Wifi P2P服务发现间歇性地工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Wifi P2P服务发现行为异常.我看到间歇性的问题,其中DNSSD侦听器不总是被调用,因此我不知道附近运行同一应用程序的设备.我正在使用以下两个API-一个用于注册要被其他设备发现的服务,另一个用于发现在其他设备上运行的附近服务.任何想法,如果我在这里做错了什么,或者在我调用这些API之前是否需要进行一些特定的其他android API调用序列,以确保无论何时注册了新服务或某项服务,始终会调用侦听器在调用API以发现本地服务之前已注册.

Wifi P2P service discovery is not behaving as expected. I am seeing intermittent issues where the DNSSD listeners are not called always and hence I have no clue of nearby devices running the same app. I am using the following two APIs - one to register a service to be discovered by other devices and the other to discover the nearby services running on other devices. Any idea if I am doing anything wrong here or is there some specific sequence of other android API calls that need to be made before I call these APIs to ensure that the listeners are always called whenever there is a new service registered or even if a service is registered before we call the API to discover the local services.

用于注册本地服务的API:

API to register a local service:

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:

API to discover local services:

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

注意:经理&频道初始化为

Note: manager & channel are initialized as

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

推荐答案

WifiP2p(通常):

前一段时间,我正在开发具有基于WifiP2pService Broadcasting/Discovery的相当复杂的网络连接系统的应用程序.基于这种经验,我已经在SO上写了几篇关于难度,磨损和问题的文章.这是其中的两个(它们充满了我通过Service Discovery获得的关于WifiP2p的内部知识,以及WifiP2p本身):

WifiP2p (in general):

Some time ago I was developing an application with a pretty complex network connectivity system based on WifiP2p with Service Broadcasting/Discovery. And based on that experience I already wrote few posts here on SO about how difficult, wearing and problematic that is. Here are two of them (they are quite full of the inside knowledge I acquired about WifiP2p with Service Discovery, and WifiP2p itself):

为什么发现Android WifiDirect的对等方如此不可靠

Wi-fi P2P.通知所有同龄人某个事件

我建议您阅读我的两个答案(即使它们更多地集中在WifiP2p本身上).他们应该给您一些有关使用WifiP2p Service Discovery时应寻找的内容的观点. 我可以轻松地说,如果您要构建一个高效,相对可靠且健壮的WifiP2p连接系统(尤其是使用Service Discovery),则必须精打细算.

I would advise you to read both of my answers (even though they are focused a bit more on the WifiP2p itself). They should give you some perspective on the things you should be looking for when working with the WifiP2p Service Discovery. I can easily say that if you want to build an efficient, relatively reliable and robust WifiP2p connection system (especially with Service Discovery), you will have to work your ass off.

为了更好地回答您的确切问题,我将告诉您我所做的(与您不同)使我的Service Discovery工作相当可靠的情况.

To better answer your exact question, I will tell you what I did (different from you) to make my Service Discovery work pretty reliably.

1.广播Service:

首先:在注册Service(使用addLocalService方法)之前,应使用WifiP2pManagerclearLocalServices方法.而且重要的是,如果通过onSuccess回调返回的clearLocalServices中传递的侦听器,则应该调用addLocalService.

First of all: before registering your Service (with addLocalService method) you should use the WifiP2pManager's clearLocalServices method. And it is important, that you should only call addLocalService if the listener passed in the clearLocalServices returned with the onSuccess callback.

尽管这很好地设置了广播,但我发现其他节点并不总是能够检测到广播的service(尤其是当这些节点在注册本地Service时尚未主动检测服务时) -但他们后来加入"了).我找不到100%可靠地解决此问题的方法.相信我,我可能正在尝试与WifiP2p相关的所有事情.不,clearLocalServices-addLocalService序列并没有给出令人满意的结果.或更重要的是:做一些不同的事情效果更好.我决定要做的是,在我成功添加了本地服务(addLocalService中的onSuccess回调)之后,我启动了一个Thread,它将定期调用WifiP2pManager的方法discoverPeers .这似乎迫使重新广播所有service信息.

Although this sets up the broadcasting pretty nicely, I found that other nodes were not always able to detect the broadcasted service (especially when those nodes weren't already actively detecting services at the moment of registering your local Service - but they "joined" later). I couldn't find a way to fix this issue 100% reliably. And believe me I was trying probably everything WifiP2p-related. And no, the clearLocalServices-addLocalService sequence wasn't really giving satisfying results. Or more so: doing something different was working much better. What I decided to do, was after I successfully added local service (onSuccess callback from addLocalService), I started a Thread that would periodically call WifiP2pManager's method discoverPeers. That seemed to be forcing to rebroadcast all the service information.

所以...基本上,您的广播代码的基础看起来应该更像这样(请注意,如果网络连接系统是在正确的状态下,您应该自己设计它们以使其最适合您的解决方案):

So... basically the base of your broadcasting code should look more-less like this (bare in mind that every single piece of code I will post here is stripped-off of all "checks" if the network connectivity system is in the right state, you should design them yourself to fit your solution the best):

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.

For the discovering of your service I used similar approach. Both with the setting up the discovering, and with trying to force "rediscovery" of services.

通过以下三种WifiP2pManager方法的顺序进行设置:

Setting up was performed with the sequence of the following three WifiP2pManager's methods:

removeServiceRequestaddServiceRequestdiscoverServices

以完全相同的顺序调用它们,只有在上一个方法通过onSuccess回调返回"之后,才调用特定方法(确切地说是第二个或第三个方法).

They were called in this exact order and a particular method (second or the third one to be exact) has been called only after the previous one had "returned" with the onSuccess callback.

services的重新发现是通过直观的方法执行的(只是通过重复上述顺序:removeServiceRequest-> addServiceRequest-> discoverServices).

The rediscovery of services was being performed with the intuitive method (just by repeating the mentioned sequence: removeServiceRequest -> addServiceRequest -> discoverServices).

我的代码基础看起来像这样(要开始Service Discovery,我先调用prepareServiceDiscovery()然后是startServiceDiscovery()):

The base of my code looked more-less like this (to start Service Discovery I would first call prepareServiceDiscovery() and then 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();
    }
};

所有这些使我的系统运行良好.它还不是很完美,但是由于缺乏有关该主题的文档,我想我不能做更多的事情来改进它.

All this made my system work quite well. It wasn't perfect yet, but with the lack of documentation on this subject I think I couldn't do much more to improve it.

如果您测试这种方法,请确保告诉我它如何为您工作(或者 if 它为您工作;)).

If you test this approach, be sure to tell me how it works for you (or if it works for you ;) ).

这篇关于Wifi P2P服务发现间歇性地工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆