安卓网络服务发现(Android NSD):为什么服务类型不匹配

3
我创建了一个应用程序来测试Android上的网络服务发现(NSD)。 失败的情况 两个设备运行该应用程序。我在第一个设备上点击“注册”,并在看到确认注册的提示后在另一个设备上点击“发现”。
第二个设备发现了该服务,但是它的类型是未知的。通过调试,我发现未知的服务类型是:
_mynsd._tcp.

但是当服务被注册时,类型被设置为

_mynsd._tcp // (without the dot at the end)

我不相信我已经做了会改变服务类型的事情。 以下是该活动:

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

这是布局:

<?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>
1个回答

1
你需要在形式上以 SRV 记录的形式在 DNS 中注册它,才能使其被识别。如果您将一个设备设置为另一个设备的名称服务器,则可能会在 localhost 上进行此注册。这里有一个解释here;这是 Cloud DNS,但任何本地名称服务器都适用于 localdomain。回答实际问题:它是绝对域名(带有尾随的.)与相对域名之间的区别。

我相信基于DNS的服务发现(DNS-SD)机制已经在系统中以某种方式实现了。 - Themelis
@Skemelio 如果没有查看NSD文档,那么target主机名和port将是最少要求的,以告诉运行发现的主机可以连接到哪里。结尾的.只在DNS条目中需要,否则不需要。 - Martin Zeitler
是的,@Martin Zeitler,有一个NsdServiceInfo对象可以将所有这些信息包装在其中,在您提供它们之后。 - Themelis
1
@Skemelio 这里有解释:http://www.dns-sd.org/trailingdotsindomainnames.html - Martin Zeitler
因此,绝对域名总是以尾随的 . 结尾。有趣的是...问题在于,在Android文档或我检查过的任何其他示例中都没有关于这成为问题的参考。 - Themelis
显示剩余2条评论

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