Android NSD not discovering all services
Asked Answered
S

6

33

I'm trying to run an application using Android Native Service Discovery but sometimes when I run the application, it doesn't discover all services from my network. I'm running the code from https://github.com/joeluchoa/nsd using four galaxy nexus and most of the times each of them discoveries different number of services at the same time.

Basically I run a service with a 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);

Then I publish it using the method registerService from NsdManager:

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

To discover the services I use the method discoverServices from NsdManager:

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

With mDiscoveryListener as follows:

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

Am i doing something wrong? Does anybody know a solution or a workaround for this?

Scrabble answered 9/10, 2012 at 12:3 Comment(4)
I camer acros your post while trying to fix an NPE that seems to popup when I have two devices in the network with the same NSD info... So, I don't have an answer for you yet, but I notice that your trying to get info that you haven't resolved in your log statement.Linhliniment
it is a common practice for all developers to follow that using try catch or print out all variables to find out the errorsAnthracene
you are only discovering services of SERVICE_TYPE, which in this example is http web servers.Jennijennica
A service that was discoverable in Android 13 is not discoverable in Android 14 using the same codes with NsdManger, I don't know if anyone else encountered this problem.Specify
H
11

To discover all services of the connected network just change the service type you are discovering,

public static final String SERVICE_TYPE = "_services._dns-sd._udp";
Heyday answered 5/12, 2018 at 10:56 Comment(1)
How does it help?Veradia
M
3

I was seeing the same issue with devices not being discovered and was able to fix it by acquiring the WifiManager Multicast lock prior to discovering services:

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)

And later releasing the lock when done discovering services:

mNsdManager.stopServiceDiscovery(mDiscoveryListener)
    
multicastLock.release()
Medicable answered 23/10, 2020 at 0:16 Comment(2)
Really saved my day, thank you so much! I was having issues with Android 13, as the target of my app is still 30. As RxDNSSD library would not work, had to switch to the native NsdManager, which works only using this lockEurythmic
I might also add that you have to make sure the multicastLock variable lives as long as your service is discovering. At least for me it seems to auto release the lock if it is no longer referenced.Beowulf
P
1

I'm afraid that there are still bugs in the implementation that cause it to miss services. I've done a couple days of testing with multiple Android devices and a MacBook, and it just doesn't work all the time. I documented my findings on a bug report over in the Android bug tracker: https://code.google.com/p/android/issues/detail?id=178080

Palembang answered 27/12, 2015 at 15:50 Comment(0)
M
1

I tend to think the whole NSD implementation in Android must be a bit flaky. I also have a simple Activity just to demonstrate the lifecycle (no Sockets are opened), and sometimes it works, and sometimes it does not work. I simply don't get it. Here is the Activity if anybody has some insight:

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

On the other hand, Wifi Direct based NSD seems to be very reliable for me:

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

Note that neither of these Activities have any resources, so just add the Activities to your Manifest with the proper permissions.

Mele answered 2/11, 2016 at 10:57 Comment(0)
S
1

It may be little late for the answer, but I found a good solution for NSD for android give on their developer site. I made a few modification and it works perfectly fine.

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

Hope it this helps

Squatness answered 31/10, 2017 at 5:40 Comment(0)
T
-1

I had the same issue, reinstall helped. Try to use:)

Telophase answered 8/10, 2014 at 15:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.