네트워크 서비스 검색 사용

네트워크 서비스 검색 (NSD)을 통해 앱이 다른 네트워크 서비스에 액세스하는 서비스에 장치가 로컬 네트워크에서 제공하는 것입니다. NSD를 지원하는 장치에는 프린터, 웹캠, HTTPS 서버 및 기타 모바일 장치가 포함됩니다.

NSD는 DNS 기반 서비스 검색 (DNS-SD) 메커니즘을 구현하며, 앱이 서비스 유형과 이름을 지정하여 서비스를 요청하도록 허용 기기 인스턴스의 이름을 뜻합니다. DNS-SD는 Android와 다른 모바일 플랫폼 모두에서 지원됩니다.

앱에 NSD를 추가하면 사용자가 기기에서 다른 기기를 식별할 수 있습니다. 로컬 네트워크를 지원해야 합니다 이는 파일 공유 또는 멀티 플레이어와 같은 다양한 P2P 애플리케이션 있습니다. Android의 NSD API는 구현에 필요한 작업을 간소화합니다. 기능을 제공합니다

이 과정에서는 리소스를 브로드캐스트할 수 있는 애플리케이션을 빌드하는 방법을 이름과 연결 정보를 로컬 네트워크에 연결하고 동일한 작업을 수행하는 다른 애플리케이션에서 가까울 수도 있습니다 마지막으로 이 강의에서는 다른 기기에서 실행 중인 동일한 애플리케이션에 연결할 수 없습니다.

네트워크에 서비스 등록

참고: 이 단계는 선택사항입니다. 만약 앱의 서비스를 로컬 네트워크를 통해 브로드캐스팅하는 것에 관심이 없습니다. 이 모듈의 뒷부분에서 다음 섹션인 네트워크에서 서비스 검색을 참조하세요.

로컬 네트워크에 서비스를 등록하려면 먼저 NsdServiceInfo 객체를 만드세요. 이 객체는 네트워크에 있는 다른 장치들이 장치에 연결할지 여부를 결정할 때 사용하는 것을 있습니다.

Kotlin

fun registerService(port: Int) {
    // Create the NsdServiceInfo object, and populate it.
    val serviceInfo = NsdServiceInfo().apply {
        // The name is subject to change based on conflicts
        // with other services advertised on the same network.
        serviceName = "NsdChat"
        serviceType = "_nsdchat._tcp"
        setPort(port)
        ...
    }
}

자바

public void registerService(int port) {
    // Create the NsdServiceInfo object, and populate it.
    NsdServiceInfo serviceInfo = new NsdServiceInfo();

    // The name is subject to change based on conflicts
    // with other services advertised on the same network.
    serviceInfo.setServiceName("NsdChat");
    serviceInfo.setServiceType("_nsdchat._tcp");
    serviceInfo.setPort(port);
    ...
}

이 코드 스니펫은 서비스 이름을 'NsdChat'으로 설정합니다. 서비스 이름 인스턴스 이름으로, 네트워크의 다른 기기에 표시되는 이름입니다. 이름은 NSD를 사용하여 네트워크상의 모든 장치에 표시됩니다. 있습니다. 이름은 네트워크에 있는 모든 서비스에 대해 고유해야 합니다. Android에서 자동으로 충돌 해결을 처리합니다. 만약 네트워크에 있는 두 장치 모두 NsdChat 애플리케이션이 설치되어 있고 서비스 이름을 "NsdChat" (1)'.

두 번째 매개변수는 서비스 유형을 설정하고, 애플리케이션 레이어입니다 구문은 다음과 같습니다. '_<protocol>._<transportlayer>'입니다. 이 서비스는 TCP를 통해 실행되는 HTTP 프로토콜을 사용합니다. 애플리케이션 프린터 서비스 (예: 네트워크 프린터)를 제공하는 경우 서비스 유형을 '_ipp._tcp'로 설정합니다.

참고: 국제 할당 번호 권한 (IANA)은 중앙 집중식, NSD 및 Bonjour와 같은 서비스 검색 프로토콜이 사용하는 서비스 유형의 신뢰할 수 있는 목록입니다. IANA 서비스 이름 및 포트 번호 목록. 새로운 서비스 유형을 사용하려면 IANA 포트 및 서비스 등록 양식을 작성하시기 바랍니다.

서비스 포트를 설정할 때는 다음과 같이 하드코딩하지 마세요. 충돌이 발생할 수 있습니다 예를 들어 포트 1337을 사용하므로 항상 포트 1337과 동일한 포트를 사용하는 다른 설치된 애플리케이션. 대신 기기의 다음 포트로 이동합니다. 이 정보는 애플리케이션이 사용하는 포트가 다른 애플리케이션에 의해 알려진 것이기 때문입니다. 대신 애플리케이션은 서비스에 연결하기 직전에 서비스 브로드캐스트에서 있습니다.

소켓을 사용하는 경우, 다음은 소켓을 0으로 설정하면 됩니다.

Kotlin

fun initializeServerSocket() {
    // Initialize a server socket on the next available port.
    serverSocket = ServerSocket(0).also { socket ->
        // Store the chosen port.
        mLocalPort = socket.localPort
        ...
    }
}

자바

public void initializeServerSocket() {
    // Initialize a server socket on the next available port.
    serverSocket = new ServerSocket(0);

    // Store the chosen port.
    localPort = serverSocket.getLocalPort();
    ...
}

이제 NsdServiceInfo 객체를 정의했으므로 RegistrationListener 인터페이스를 구현해야 합니다. 이 인터페이스에는 애플리케이션에 서비스 등록 및 등록 취소의 성공 또는 실패

Kotlin

private val registrationListener = object : NsdManager.RegistrationListener {

    override fun onServiceRegistered(NsdServiceInfo: NsdServiceInfo) {
        // Save the service name. Android may have changed it in order to
        // resolve a conflict, so update the name you initially requested
        // with the name Android actually used.
        mServiceName = NsdServiceInfo.serviceName
    }

    override fun onRegistrationFailed(serviceInfo: NsdServiceInfo, errorCode: Int) {
        // Registration failed! Put debugging code here to determine why.
    }

    override fun onServiceUnregistered(arg0: NsdServiceInfo) {
        // Service has been unregistered. This only happens when you call
        // NsdManager.unregisterService() and pass in this listener.
    }

    override fun onUnregistrationFailed(serviceInfo: NsdServiceInfo, errorCode: Int) {
        // Unregistration failed. Put debugging code here to determine why.
    }
}

자바

public void initializeRegistrationListener() {
    registrationListener = new NsdManager.RegistrationListener() {

        @Override
        public void onServiceRegistered(NsdServiceInfo NsdServiceInfo) {
            // Save the service name. Android may have changed it in order to
            // resolve a conflict, so update the name you initially requested
            // with the name Android actually used.
            serviceName = NsdServiceInfo.getServiceName();
        }

        @Override
        public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
            // Registration failed! Put debugging code here to determine why.
        }

        @Override
        public void onServiceUnregistered(NsdServiceInfo arg0) {
            // Service has been unregistered. This only happens when you call
            // NsdManager.unregisterService() and pass in this listener.
        }

        @Override
        public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
            // Unregistration failed. Put debugging code here to determine why.
        }
    };
}

이제 서비스를 등록할 모든 준비가 완료되었습니다. 메서드 호출 registerService()

이 메서드는 비동기식이므로 실행해야 하는 모든 코드는 서비스가 등록된 후에는 onServiceRegistered() 메서드로 이동해야 합니다.

Kotlin

fun registerService(port: Int) {
    // Create the NsdServiceInfo object, and populate it.
    val serviceInfo = NsdServiceInfo().apply {
        // The name is subject to change based on conflicts
        // with other services advertised on the same network.
        serviceName = "NsdChat"
        serviceType = "_nsdchat._tcp"
        setPort(port)
    }

    nsdManager = (getSystemService(Context.NSD_SERVICE) as NsdManager).apply {
        registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, registrationListener)
    }
}

자바

public void registerService(int port) {
    NsdServiceInfo serviceInfo = new NsdServiceInfo();
    serviceInfo.setServiceName("NsdChat");
    serviceInfo.setServiceType("_http._tcp.");
    serviceInfo.setPort(port);

    nsdManager = Context.getSystemService(Context.NSD_SERVICE);

    nsdManager.registerService(
            serviceInfo, NsdManager.PROTOCOL_DNS_SD, registrationListener);
}

네트워크에서 서비스 검색

이 네트워크는 야수 같은 네트워크 프린터에서 온순한 네트워크 웹캠, 근처 틱택토의 잔혹하고 격렬한 전투까지 있습니다. 애플리케이션에서 이 활기 넘치는 생태계를 확인할 수 있도록 서비스 검색입니다 애플리케이션이 서비스를 수신 대기해야 함 네트워크에 브로드캐스트하여 어떤 서비스를 사용할 수 있는지 확인하고 애플리케이션이 작동할 수 없는 모든 것을 처리합니다.

서비스 등록과 같은 서비스 검색에는 두 단계가 있습니다. 관련 콜백으로 검색 리스너를 설정하고 단일 비동기식 discoverServices()에 대한 API 호출

먼저 NsdManager.DiscoveryListener를 구현하는 익명 클래스를 인스턴스화합니다. 다음 스니펫은 간단한 예:

Kotlin

// Instantiate a new DiscoveryListener
private val discoveryListener = object : NsdManager.DiscoveryListener {

    // Called as soon as service discovery begins.
    override fun onDiscoveryStarted(regType: String) {
        Log.d(TAG, "Service discovery started")
    }

    override fun onServiceFound(service: NsdServiceInfo) {
        // A service was found! Do something with it.
        Log.d(TAG, "Service discovery success$service")
        when {
            service.serviceType != SERVICE_TYPE -> // Service type is the string containing the protocol and
                // transport layer for this service.
                Log.d(TAG, "Unknown Service Type: ${service.serviceType}")
            service.serviceName == mServiceName -> // The name of the service tells the user what they'd be
                // connecting to. It could be "Bob's Chat App".
                Log.d(TAG, "Same machine: $mServiceName")
            service.serviceName.contains("NsdChat") -> nsdManager.resolveService(service, resolveListener)
        }
    }

    override fun onServiceLost(service: NsdServiceInfo) {
        // When the network service is no longer available.
        // Internal bookkeeping code goes here.
        Log.e(TAG, "service lost: $service")
    }

    override fun onDiscoveryStopped(serviceType: String) {
        Log.i(TAG, "Discovery stopped: $serviceType")
    }

    override fun onStartDiscoveryFailed(serviceType: String, errorCode: Int) {
        Log.e(TAG, "Discovery failed: Error code:$errorCode")
        nsdManager.stopServiceDiscovery(this)
    }

    override fun onStopDiscoveryFailed(serviceType: String, errorCode: Int) {
        Log.e(TAG, "Discovery failed: Error code:$errorCode")
        nsdManager.stopServiceDiscovery(this)
    }
}

자바

public void initializeDiscoveryListener() {

    // Instantiate a new DiscoveryListener
    discoveryListener = new NsdManager.DiscoveryListener() {

        // Called as soon as service discovery begins.
        @Override
        public void onDiscoveryStarted(String regType) {
            Log.d(TAG, "Service discovery started");
        }

        @Override
        public void onServiceFound(NsdServiceInfo service) {
            // A service was found! Do something with it.
            Log.d(TAG, "Service discovery success" + service);
            if (!service.getServiceType().equals(SERVICE_TYPE)) {
                // Service type is the string containing the protocol and
                // transport layer for this service.
                Log.d(TAG, "Unknown Service Type: " + service.getServiceType());
            } else if (service.getServiceName().equals(serviceName)) {
                // The name of the service tells the user what they'd be
                // connecting to. It could be "Bob's Chat App".
                Log.d(TAG, "Same machine: " + serviceName);
            } else if (service.getServiceName().contains("NsdChat")){
                nsdManager.resolveService(service, resolveListener);
            }
        }

        @Override
        public void onServiceLost(NsdServiceInfo service) {
            // When the network service is no longer available.
            // Internal bookkeeping code goes here.
            Log.e(TAG, "service lost: " + service);
        }

        @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);
            nsdManager.stopServiceDiscovery(this);
        }

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

NSD API는 이 인터페이스의 메서드를 사용하여 검색 시 애플리케이션에 정보를 제공합니다. 서비스를 찾거나 사용할 수 없을 때 (손실은 'is 더 이상 사용할 수 없음'). 이 스니펫은 서비스를 찾을 때

  1. 찾은 서비스의 서비스 이름을 서비스와 비교합니다. 기기가 방금 자체 데이터를 수신했는지 확인하기 위한 로컬 서비스의 이름 브로드캐스트 (유효함)를 제공합니다.
  2. 서비스 유형을 선택하여 해당 서비스가 조직의 서비스 유형인지 확인합니다. 연결할 수 있습니다.
  3. 서비스 이름을 확인하여 올바른 애플리케이션입니다.

서비스 이름을 확인하는 것이 항상 필요한 것은 아니며, 연결할 수 있습니다. 예를 들어 애플리케이션은 다른 장치에서 실행되는 자체 인스턴스에만 연결하려고 합니다. 그러나 네트워크 프린터에 연결하려는 경우 서비스 유형이 네트워크 프린터에 연결되어 있는지 '_ipp._tcp'입니다.

리스너를 설정한 후 discoverServices()를 호출하여 서비스 유형을 전달합니다. 그리고 사용할 검색 프로토콜 및 방금 만든 리스너입니다.

Kotlin

nsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, discoveryListener)

자바

nsdManager.discoverServices(
        SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, discoveryListener);

네트워크에서 서비스 연결

애플리케이션이 네트워크에서 연결할 서비스를 찾으면 먼저 해당 서비스에 대한 연결 정보를 resolveService() 메서드를 사용하여 지도 가장자리에 패딩을 추가할 수 있습니다. NsdManager.ResolveListener를 구현하여 메서드를 사용하고, 이를 사용하여 NsdServiceInfo 연결 정보를 볼 수 있습니다.

Kotlin

private val resolveListener = object : NsdManager.ResolveListener {

    override fun onResolveFailed(serviceInfo: NsdServiceInfo, errorCode: Int) {
        // Called when the resolve fails. Use the error code to debug.
        Log.e(TAG, "Resolve failed: $errorCode")
    }

    override fun onServiceResolved(serviceInfo: NsdServiceInfo) {
        Log.e(TAG, "Resolve Succeeded. $serviceInfo")

        if (serviceInfo.serviceName == mServiceName) {
            Log.d(TAG, "Same IP.")
            return
        }
        mService = serviceInfo
        val port: Int = serviceInfo.port
        val host: InetAddress = serviceInfo.host
    }
}

자바

public void initializeResolveListener() {
    resolveListener = new NsdManager.ResolveListener() {

        @Override
        public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
            // Called when the resolve fails. Use the error code to debug.
            Log.e(TAG, "Resolve failed: " + errorCode);
        }

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

            if (serviceInfo.getServiceName().equals(serviceName)) {
                Log.d(TAG, "Same IP.");
                return;
            }
            mService = serviceInfo;
            int port = mService.getPort();
            InetAddress host = mService.getHost();
        }
    };
}

서비스가 확인되면 애플리케이션에서 자세한 IP 주소 및 포트 번호를 포함하여 서비스 정보가 포함됩니다. 모든 정보 서비스에 대한 자체 네트워크 연결을 만들어야 합니다.

애플리케이션을 닫을 때 서비스 등록 취소

NSD를 사용 설정 및 중지하는 것이 중요 애플리케이션의 실행 도중에 적절한 기능을 수명 주기 동안 사용됩니다 애플리케이션이 종료될 때 등록을 취소하면 다른 응용 프로그램이 여전히 활성 상태라고 생각하고 있습니다. 또한 서비스 검색은 비용이 많이 드는 작업이므로 는 상위 활동이 일시중지되고 활동이 일시중지되면 다시 사용 설정됩니다. 재개됨. 기본 활동의 수명 주기 메서드를 재정의하고 코드를 삽입합니다. 서비스 브로드캐스트와 검색을 적절히 시작 및 중지할 수 있습니다.

Kotlin

    // In your application's Activity

    override fun onPause() {
        nsdHelper?.tearDown()
        super.onPause()
    }

    override fun onResume() {
        super.onResume()
        nsdHelper?.apply {
            registerService(connection.localPort)
            discoverServices()
        }
    }

    override fun onDestroy() {
        nsdHelper?.tearDown()
        connection.tearDown()
        super.onDestroy()
    }

    // NsdHelper's tearDown method
    fun tearDown() {
        nsdManager.apply {
            unregisterService(registrationListener)
            stopServiceDiscovery(discoveryListener)
        }
    }

Java

    // In your application's Activity

    @Override
    protected void onPause() {
        if (nsdHelper != null) {
            nsdHelper.tearDown();
        }
        super.onPause();
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (nsdHelper != null) {
            nsdHelper.registerService(connection.getLocalPort());
            nsdHelper.discoverServices();
        }
    }

    @Override
    protected void onDestroy() {
        nsdHelper.tearDown();
        connection.tearDown();
        super.onDestroy();
    }

    // NsdHelper's tearDown method
    public void tearDown() {
        nsdManager.unregisterService(registrationListener);
        nsdManager.stopServiceDiscovery(discoveryListener);
    }