I've created an app to test the network service discovery (NSD) on android.
The failing scenario
Two devices running the app. I hit register on the first device and after I see a toast that confirms the registration I hit discover on the other.
The service is discovered by the second device but it's type its unknown. From debuging I saw that the unknown service type is
_mynsd._tcp.
but when the service is registered the type is set to
_mynsd._tcp // (without the dot at the end)
I don't believe I have done something that changes the service type. Here is the Activity:
public class MainActivity extends AppCompatActivity {
private static final String SERVICE_TYPE = "_mynsd._tcp";
private ServerSocket serverSocket;
private int localPort;
private NsdManager.RegistrationListener registrationListener;
private NsdManager.DiscoveryListener discoveryListener;
private NsdManager nsdManager;
private String serviceName;
private NsdServiceInfo service;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initializeRegistrationListener();
initializeServerSocket();
nsdManager = (NsdManager) getSystemService(NSD_SERVICE);
}
public void onRegisterClicked(View view) {
registerService(localPort);
}
public void onDiscoverClicked(View view) {
if (discoveryListener == null)
initializeDiscoveryListener();
nsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, discoveryListener);
}
public void onConnectClicked(View view) {
}
@Override
protected void onPause() {
super.onPause();
if (nsdManager != null)
nsdManager.unregisterService(registrationListener);
}
public void registerService(int port) {
NsdServiceInfo serviceInfo = new NsdServiceInfo();
serviceInfo.setServiceName("MyNsd");
serviceInfo.setServiceType(SERVICE_TYPE);
serviceInfo.setPort(port);
nsdManager.registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, registrationListener);
}
public void initializeServerSocket() {
try {
serverSocket = new ServerSocket(0);
localPort = serverSocket.getLocalPort();
} catch (IOException e) {
Toast.makeText(this, "Error with server socket", Toast.LENGTH_SHORT).show();
}
}
public void initializeDiscoveryListener() {
discoveryListener = new NsdManager.DiscoveryListener() {
@Override
public void onStartDiscoveryFailed(String s, int i) {
Toast.makeText(MainActivity.this, "Start discovery failed", Toast.LENGTH_SHORT).show();
}
@Override
public void onStopDiscoveryFailed(String s, int i) {
Toast.makeText(MainActivity.this, "Stop discovery failed ", Toast.LENGTH_SHORT).show();
}
@Override
public void onDiscoveryStarted(String s) {
Toast.makeText(MainActivity.this, "Started discovery", Toast.LENGTH_SHORT).show();
}
@Override
public void onDiscoveryStopped(String s) {
Toast.makeText(MainActivity.this, "Stopped discovery", Toast.LENGTH_SHORT).show();
}
@Override
public void onServiceFound(NsdServiceInfo nsdServiceInfo) {
Toast.makeText(MainActivity.this, nsdServiceInfo.getServiceName() + " service found", Toast.LENGTH_SHORT).show();
if (!nsdServiceInfo.getServiceType().equals(SERVICE_TYPE)) {
Toast.makeText(MainActivity.this, "Unknown service type "+nsdServiceInfo.getServiceType(), Toast.LENGTH_SHORT).show();
} else if (nsdServiceInfo.getServiceName().equals(serviceName)) {
// The one who registered the service is the one which actually holds the
// service name and its not null, so if we are here its the same machine
// who registered the service in the first place.
Toast.makeText(MainActivity.this, "Same machine: " + serviceName, Toast.LENGTH_SHORT).show();
} else if (nsdServiceInfo.getServiceName().contains("MyNsd")) {
nsdManager.resolveService(nsdServiceInfo, new NsdManager.ResolveListener() {
@Override
public void onResolveFailed(NsdServiceInfo nsdServiceInfo, int i) {
Toast.makeText(MainActivity.this, "Could not resolve " + nsdServiceInfo.getServiceName(), Toast.LENGTH_SHORT).show();
}
@Override
public void onServiceResolved(NsdServiceInfo nsdServiceInfo) {
Toast.makeText(MainActivity.this, "Resolved " + nsdServiceInfo.getServiceName(), Toast.LENGTH_SHORT).show();
if (nsdServiceInfo.getServiceName().equals(serviceName)){
Toast.makeText(MainActivity.this, "Same IP", Toast.LENGTH_SHORT).show();
return;
}
service = nsdServiceInfo;
int port = service.getPort();
InetAddress host = service.getHost();
}
});
}
}
@Override
public void onServiceLost(NsdServiceInfo nsdServiceInfo) {
Toast.makeText(MainActivity.this, nsdServiceInfo.getServiceName() + " service lost", Toast.LENGTH_SHORT).show();
}
};
}
public void initializeRegistrationListener() {
registrationListener = new NsdManager.RegistrationListener() {
@Override
public void onRegistrationFailed(NsdServiceInfo nsdServiceInfo, int i) {
Toast.makeText(MainActivity.this, "Registration failed!", Toast.LENGTH_SHORT).show();
}
@Override
public void onUnregistrationFailed(NsdServiceInfo nsdServiceInfo, int i) {
Toast.makeText(MainActivity.this, "Unregistration failed", Toast.LENGTH_SHORT).show();
}
@Override
public void onServiceRegistered(NsdServiceInfo nsdServiceInfo) {
Toast.makeText(MainActivity.this, "Service registered", Toast.LENGTH_SHORT).show();
serviceName = nsdServiceInfo.getServiceName();
}
@Override
public void onServiceUnregistered(NsdServiceInfo nsdServiceInfo) {
Toast.makeText(MainActivity.this, "Service unregistered", Toast.LENGTH_SHORT).show();
}
};
}
}
and here is the layout:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/register"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:onClick="onRegisterClicked"
android:text="Register"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/discover"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:onClick="onDiscoverClicked"
android:text="Discover"
app:layout_constraintStart_toEndOf="@+id/register"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/connect"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:onClick="onConnectClicked"
android:text="connect"
app:layout_constraintStart_toEndOf="@+id/discover"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
you have to register it in DNS
in form of a SRV
record, only then it would become known. possibly, if you would set one device as the name-server for the other device, this registration on the localhost
might work out. explained it once here; that's Cloud DNS, but any local name-server would suffice for localdomain
.
to answer the actual question: it's absolute domain name (with a trailing .
) vs. relative domain name.