How to get IP and PORT of a service published by AVAHI in iOS swift?

1.7k Views Asked by At

I am using NSNetServiceBrowser and is able to find service list published by AVAHI in "didFindService" which looks like : Service appeared: local. _https._tcp. TEMP-Mobileyes5-1C497B9ED382 -1 Service appeared: local. _https._tcp. TEMP-Mobileyes5-1C497B8E3916 -1 Service appeared: local. _https._tcp. TEMP-Mobileyes5-1C497B9ED380 -1

But not able to find IP Address and Port number of same service. I have found that code is not reaching in "netServiceDidResolveAddress" My Code is :

class ServiceDiscovery : NSObject, NSNetServiceBrowserDelegate,NSNetServiceDelegate {

    var _browser:NSNetServiceBrowser!
    var _service: NSNetService!
    var services = [NSNetService]()
    override init() {
        _browser = NSNetServiceBrowser()
        super.init()
        _browser.delegate = self
        _browser.includesPeerToPeer = true
        _browser.searchForServicesOfType("_https._tcp.", inDomain: "local.")
        _browser.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)

    }


    func netServiceBrowser(browser: NSNetServiceBrowser, didFindDomain domainString: String, moreComing: Bool) {
        print(domainString)
    }

    func netServiceBrowser(aNetServiceBrowser: NSNetServiceBrowser, didFindService aNetService: NSNetService, moreComing: Bool) {
       print("Service appeared: \(aNetService)")
        services.append(aNetService)
        aNetService.delegate = self
        aNetService.resolveWithTimeout(5.0)
    }


    func netServiceBrowser(browser: NSNetServiceBrowser, didNotSearch errorDict: [String : NSNumber]) {
        print(errorDict)
    }

    func netServiceBrowser(browser: NSNetServiceBrowser, didRemoveService service: NSNetService, moreComing: Bool) {
        print("Service removed: \(service)")

    }

    func netService(sender: NSNetService, didNotResolve errorDict: [String : NSNumber]) {
        print(errorDict)
    }

    func netServiceDidResolveAddress(sender: NSNetService) {
        print(sender.addresses![0])
    }


}
2

There are 2 best solutions below

3
On

The possible reason for your problem could be that you are calling the

aNetService.resolveWithTimeout(5.0)

inside another function, so as soon as

didFindService

finishes, the local variable aNetService gets destroyed (as it is a local variable for didFindService function)

SOLUTION

I see that you've already defined a variable at the top with class-wide scope named "_service" Hence, use that by using

_service = aNetService
_service.resolveWithTimeout(5.0)

inside your didFindService this should solve your problem. And, netServiceDidResolveAddress should get called now.

0
On
import Foundation
class ServiceDiscovery : NSObject, NetServiceBrowserDelegate,NetServiceDelegate {

    var _browser:NetServiceBrowser!
    var _service: NetService!
    var services = [NetService]()


    func searchServices(){
        self.services.removeAll()
        _browser = NetServiceBrowser()
        _browser.delegate = self
        _browser.includesPeerToPeer = true
        _browser.searchForServices(ofType: "_https._tcp.", inDomain: "local.")
        _browser.schedule(in: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode)
    }


    func updateInterface () {
        for service in self.services {
            if service.port == -1 {
                print("service \(service.name) of type \(service.type)" +
                    " not yet resolved")
                service.delegate = self
                service.resolve(withTimeout: 0.0)
            } else {

                let deviceLanController = DeviceLanController()
                let dict = NetService.dictionary(fromTXTRecord: service.txtRecordData()!)
                let id = self.copyStringFromTXTDict(dict as [AnyHashable: Any]?, which: "id")
                var ipAdd = ""
                if let address = service.addresses{
                if let addressOfFirstDevice = address.first{
                    let theAddress = addressOfFirstDevice as Data
                    var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
                    if getnameinfo((theAddress as NSData).bytes.bindMemory(to: sockaddr.self, capacity: theAddress.count), socklen_t(theAddress.count),
                                   &hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST) == 0 {
                        if let numAddress = String(validatingUTF8: hostname) {
                            ipAdd = numAddress
                        }
                    }

                    if let serviceId = id{
                        deviceLanController.setDeviceAvailable(serviceId, host: ipAdd, port: "\(service.port)")
                    }
                }
                }
            }
        }
    }


    fileprivate func copyStringFromTXTDict(_ dict: [AnyHashable: Any]?, which: String) -> String? {
        // Helper for getting information from the TXT data
        var resultString: String? = nil
        if let data = dict?[which as NSObject] as! Data? {
            resultString = String(data: data, encoding: String.Encoding.utf8)!

        }
        return resultString
    }



    func netServiceBrowser(_ browser: NetServiceBrowser, didFindDomain domainString: String, moreComing: Bool) {
        print("didFindDomain")
        print(domainString)
    }

    func netServiceBrowser(_ aNetServiceBrowser: NetServiceBrowser, didFind aNetService: NetService, moreComing: Bool) {
        print("didFindService")
        self.services.append(aNetService)
        if !moreComing {
            aNetService.stop()
            self.updateInterface()
        }
    }

    func netServiceBrowser(_ browser: NetServiceBrowser, didRemove service: NetService, moreComing: Bool){
        print("didRemoveService")
        if let ix = self.services.index(of: service) {
            self.services.remove(at: ix)
            print("removing a service")
            if !moreComing {
                self.updateInterface()
            }
        }
    }

    func netServiceBrowser(_ browser: NetServiceBrowser, didNotSearch errorDict: [String : NSNumber]) {
        print("didNotSearch")
        print(errorDict)
    }



    func netService(_ sender: NetService, didNotResolve errorDict: [String : NSNumber]) {
        print("didNotResolve",sender)
        print(errorDict)

    }

    func netServiceWillResolve(_ sender: NetService) {
        print("netServiceWillResolve",sender)
    }
    func netServiceDidResolveAddress(_ sender: NetService) {
        print("netServiceDidResolveAddress",sender)
       self.updateInterface()
    }

}

This answer solved my problem. I am resolving and saving each address in my coredata so i can use that address for connecting local services.