Wifi P2P 服务发现间歇性工作
Posted
技术标签:
【中文标题】Wifi P2P 服务发现间歇性工作【英文标题】:Wifi P2P service discovery works intermittently 【发布时间】:2014-10-10 13:41:34 【问题描述】:Wifi 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");
);
注意:manager & channel 初始化为
WifiP2pManager manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
Channel channel = manager.initialize(this, getMainLooper(), null);
【问题讨论】:
我遇到了同样的事情,有时会发生对 DnsSdServiceResponseListener 的回调。您是否找出原因或这不是一个稳定的功能? 【参考方案1】:WifiP2p
(一般):
前段时间,我正在开发一个基于WifiP2p
和Service Broadcasting/Discovery
的非常复杂的网络连接系统的应用程序。基于那次经验,我已经在这里写了几篇关于 SO 的文章,说明这是多么困难、磨损和有问题。以下是其中的两个(它们完全是我获得的关于WifiP2p
和Service Discovery
和WifiP2p
本身的内部知识):
Why is discovering peers for Android WifiDirect so unreliable
Wi-fi P2P. Inform all peers available of some event
我建议您阅读我的两个答案(即使它们更多地关注WifiP2p
本身)。他们应该让您对使用WifiP2p Service Discovery
时应该寻找的东西有一些看法。
我可以轻松地说,如果你想构建一个高效、相对可靠和健壮的WifiP2p
连接系统(尤其是Service Discovery
),你将不得不努力工作。
WifiP2p Service Discovery
:
为了更好地回答您的确切问题,我将告诉您我做了什么(与您不同)以使我的 Service Discovery
工作得非常可靠。
1.广播Service
:
首先:在注册您的Service
(使用addLocalService
方法)之前,您应该使用WifiP2pManager
的clearLocalServices
方法。重要的是,您应该仅在侦听器通过clearLocalServices
与onSuccess
回调一起返回时调用addLocalService
。
虽然这很好地设置了广播,但我发现其他节点并不总是能够检测到广播的service
(尤其是当这些节点在注册本地Service
时还没有主动检测服务时) - 但他们后来“加入”了)。我找不到 100% 可靠地解决此问题的方法。相信我,我可能正在尝试所有与WifiP2p
相关的东西。不,clearLocalServices
-addLocalService
序列并没有真正给出令人满意的结果。或者更重要的是:做一些不同的事情会更好。我决定做的是,在我成功添加本地服务(addLocalService
的onSuccess
回调)之后,我启动了一个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
的重新发现是通过直观的方法执行的(只需重复上述顺序: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();
;
所有这些都使我的系统运行良好。它还不完美,但由于缺乏关于这个主题的文档,我认为我无法做更多的改进。
如果您测试此方法,请务必告诉我它如何为您工作(或 如果它对您有效;))。
【讨论】:
我尝试了您的方法,它比 Google 提供的文档教程效果更好。但是我还是遇到了一个问题:服务发现能够发现其他设备广播一段时间的服务,然后一段时间什么都没有发现,然后这个过程重复:看到服务->没有->服务- > 没什么……你觉得呢?是硬件问题还是系统本身的问题? 这很难说实话...我记得它并不完美,有时用户必须等待几秒钟才能发现其他设备(服务)。我真的找不到解决这个问题的方法。您描述的问题可能也发生在我身上,我只是没有看到模式(服务 -> 没有 -> 服务 -> 没有...)。 我发现发布阶段应该始终在发现阶段之前进行。否则,发现将不会返回任何内容。 @RichardWong,我想你看到的是发现超时,检查这个 android 问题:code.google.com/p/android/issues/detail?id=206123 .. 解决方法是每 2 分钟强制发现一次 @BartekLipinski 感谢您提供代码示例。我已经实现了类似的东西,它确实有效。但是,它以某种方式阻止我的手机连接到任何 wifi 网络。你有没有注意到这样的事情?【参考方案2】:如果问题是服务检测,我相信创建组是使设备和服务可检测的最佳方式,但如果在所有设备中创建组,则您无法直接连接。 但作为wifi网络。 我每天都这样做,而且效果很好。
【讨论】:
以上是关于Wifi P2P 服务发现间歇性工作的主要内容,如果未能解决你的问题,请参考以下文章
在wifi-direct p2p连接中获取对等设备的IP地址[重复]
Wifi Direct P2P 无法在 Android 10+ 设备上运行,无法发现设备