Android NSD无法发现所有服务。

32
我将为您翻译这段内容。该段落涉及到编程和应用程序开发,主要是关于 Android 原生服务发现的应用。有时候在运行应用程序时,它无法从我的网络中发现所有的服务。我使用四个 Galaxy Nexus 设备从 https://github.com/joeluchoa/nsd 运行代码,大多数情况下,它们每个设备同时发现不同数量的服务。基本上,我使用 ServerSocket 运行一个服务:
ServerSocket server = new ServerSocket(0);
Log.i(TAG, "IP " + server.getInetAddress()
        + ", running on port " + server.getLocalPort());

Intent intent = new Intent(MySocket.this,
        MyPresence.class);
intent.putExtra("PORT", server.getLocalPort());
startService(intent);

然后我使用NsdManager的registerService方法进行发布:
NsdServiceInfo serviceInfo = new NsdServiceInfo();

serviceInfo.setServiceName(Build.SERIAL + "-" + new Date().getTime());
serviceInfo.setServiceType(SERVICE_TYPE);
serviceInfo.setPort(port);

mNsdManager.registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD,
        mRegistrationListener);

要发现我使用的服务,我使用NsdManager中的discoverServices方法:

mNsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD,
        mDiscoveryListener);

使用以下mDiscoveryListener:
mDiscoveryListener = new NsdManager.DiscoveryListener() {

    @Override
    public void onDiscoveryStarted(String regType) {
        Log.d(TAG, "Service discovery started");
    }

    @Override
    public void onServiceFound(NsdServiceInfo service) {
        Log.d(TAG, "Service discovery success");
        Log.d(TAG, String.format("%s %s %s %d",
                service.getServiceName(), service.getServiceType(),
                service.getHost(), service.getPort()));
        if (!service.getServiceType().contains(SERVICE_TYPE)) {
            Log.d(TAG,
                    "Unknown Service Type: " + service.getServiceType());
        } else if (service.getServiceName().equals(mServiceName)) {
            Log.d(TAG, "Same machine: " + mServiceName);
        } else {
            mNsdManager.resolveService(service, mResolveListener);
        }
    }

    @Override
    public void onServiceLost(NsdServiceInfo service) {
        Log.e(TAG, "service lost" + service);
    }

    @Override
    public void onDiscoveryStopped(String serviceType) {
        Log.i(TAG, serviceType + " Discovery stopped: " + serviceType);
    }

    @Override
    public void onStartDiscoveryFailed(String serviceType, int errorCode) {
        Log.e(TAG, serviceType + " Discovery failed: Error code:"
                + errorCode);
        mNsdManager.stopServiceDiscovery(this);
    }

    @Override
    public void onStopDiscoveryFailed(String serviceType, int errorCode) {
        Log.e(TAG, serviceType + " Discovery failed: Error code:"
                + errorCode);
        mNsdManager.stopServiceDiscovery(this);
    }
};

我做错了什么吗?有人知道解决方案或解决方法吗?


我在尝试修复一个NPE时遇到了你的帖子,当我在网络中有两个具有相同NSD信息的设备时,它似乎会弹出...所以,我还没有答案,但我注意到你正在尝试获取你在日志语句中没有解决的信息。 - Brill Pappin
2
所有开发人员都遵循的常见做法是使用try catch或打印所有变量以查找错误。 - Jeff Bootsholz
你只是在发现SERVICE_TYPE服务,这个例子中是http web服务器。 - Callum Wilson
6个回答

11

要发现连接的网络中的所有服务,只需更改您正在发现的服务类型,

public static final String SERVICE_TYPE = "_services._dns-sd._udp";

1
它如何帮助? - Nayan

3

我遇到了设备无法被发现的问题,通过在发现服务之前获取WifiManager的组播锁定,我成功地解决了这个问题:

val multicastLock: WifiManager.MulticastLock = (mContext.getSystemService(Context.WIFI_SERVICE) as WifiManager).createMulticastLock(TAG)
multicastLock.setReferenceCounted(true)
    
multicastLock.acquire()
    
mNsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener)

在完成服务发现后,释放锁定:

mNsdManager.stopServiceDiscovery(mDiscoveryListener)
    
multicastLock.release()

2
真的救了我的一天,非常感谢!我在使用Android 13时遇到了问题,因为我的应用程序的目标仍然是30。由于RxDNSSD库无法工作,不得不切换到本地的NsdManager,这只能使用此锁定来工作。 - mmx2
我还要补充一点,您必须确保multicastLock变量的生命周期与您的服务发现一样长。至少对我来说,如果不再引用它,它似乎会自动释放锁定。 - Arne Fischer

1

可能回答有点晚,但我在NSD的开发者网站上找到了一个好的解决方案。我进行了一些修改,现在它可以完美地运行在Android上。

public class NsdClient {
private Context mContext;

private NsdManager mNsdManager;
NsdManager.DiscoveryListener mDiscoveryListener;

//To find all the available networks SERVICE_TYPE = "_services._dns-sd._udp"
public static final String SERVICE_TYPE = "_hap._tcp.";
public static final String TAG = "NsdClient";

private static ArrayList<NsdServiceInfo> ServicesAvailable = new ArrayList<>();

public NsdClient(Context context) {
    mContext = context;
    mNsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
}

public void initializeNsd() {
    initializeDiscoveryListener();
}

public void initializeDiscoveryListener() {
    mDiscoveryListener = new NsdManager.DiscoveryListener() {

        @Override
        public void onDiscoveryStarted(String regType) {
            Log.d(TAG, "Service discovery started " + regType);
        }

        @Override
        public void onServiceFound(NsdServiceInfo service) {
            Log.d(TAG, "Service discovery success " + service);
            AVAILABLE_NETWORKS.add(service);

            if (!service.getServiceType().equals(SERVICE_TYPE)) {
                Log.d(TAG, "Unknown Service Type: " + service.getServiceType());
            } else if (service.getServiceName().equals(mServiceName)) {
                Log.d(TAG, "Same Machine: " + mServiceName);
            } else if (service.getServiceName().contains(mServiceName)) {
                Log.d(TAG, "Resolving Services: " + service);
                mNsdManager.resolveService(service, new initializeResolveListener());
            }
        }

        @Override
        public void onServiceLost(NsdServiceInfo service) {
            Log.e(TAG, "service lost" + service);
            if (ServicesAvailable.equals(service)) {
                ServicesAvailable = null;
            }
        }

        @Override
        public void onDiscoveryStopped(String serviceType) {
            Log.i(TAG, "Discovery stopped: " + serviceType);
        }

        @Override
        public void onStartDiscoveryFailed(String serviceType, int errorCode) {
            Log.e(TAG, "Discovery failed: Error code:" + errorCode);
            mNsdManager.stopServiceDiscovery(this);
        }

        @Override
        public void onStopDiscoveryFailed(String serviceType, int errorCode) {
            Log.e(TAG, "Discovery failed: Error code:" + errorCode);
            mNsdManager.stopServiceDiscovery(this);
        }
    };
}

public class initializeResolveListener implements NsdManager.ResolveListener {

    @Override
    public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
        Log.e(TAG, "Resolve failed " + errorCode);
        switch (errorCode) {
            case NsdManager.FAILURE_ALREADY_ACTIVE:
                Log.e(TAG, "FAILURE ALREADY ACTIVE");
                mNsdManager.resolveService(serviceInfo, new initializeResolveListener());
                break;
            case NsdManager.FAILURE_INTERNAL_ERROR:
                Log.e(TAG, "FAILURE_INTERNAL_ERROR");
                break;
            case NsdManager.FAILURE_MAX_LIMIT:
                Log.e(TAG, "FAILURE_MAX_LIMIT");
                break;
        }
    }

    @Override
    public void onServiceResolved(NsdServiceInfo serviceInfo) {
        Log.e(TAG, "Resolve Succeeded. " + serviceInfo);


        if (serviceInfo.getServiceName().equals(mServiceName)) {
            Log.d(TAG, "Same IP.");
            return;
        }

    }
}

public void stopDiscovery() {
    mNsdManager.stopServiceDiscovery(mDiscoveryListener);
}

public List<NsdServiceInfo> getChosenServiceInfo() {
    return ServicesAvailable;
}

public void discoverServices() {
    mNsdManager.discoverServices(
            SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);
}
}

希望这有所帮助。

1
我倾向于认为安卓中整个NSD实现可能有点不稳定。我还有一个简单的Activity,只是为了演示生命周期(没有打开套接字),有时它可以工作,有时它不能工作。我就是不明白。如果有人有见解,这里是Activity:

https://github.com/mholzel/Dump/blob/master/NetworkServiceDiscoveryViaWifi.java

另一方面,基于Wifi Direct的NSD对我来说似乎非常可靠:

https://github.com/mholzel/Dump/blob/master/NetworkServiceDiscoveryViaWifiDirect.java

请注意,这两个活动都没有任何资源,所以只需使用适当的权限将这些活动添加到您的清单中即可。

1

-1

我曾经遇到过同样的问题,重新安装解决了。你可以试试:)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接