yes, I need to connect with all devices with this service. I send a httpRequest and get some parameter from all devices. Then I create a dynamic ListView to show DeviceInformations like Devicename, temperature, lightstate...
i find out that all devices have hostname like
device.local
device-1.local
device-2.local
....
so I have the best results if search with a for_loop
private func fillHostName()
{
let number = 30
var counter = 0
self.hostNames.removeAll()
if newHostNames.count == 0 {
while counter < number {
if counter == 0
{
self.hostNames.append(String("device.local"))
}
else
{
self.hostNames.append(String("device-\(counter).local"))
}
counter += 1
}
}
else
{
self.hostNames = self.newHostNames
}
}
self.hostNames.forEach{ host in
self.getMeshInfo(from: host)
usleep(80000)
}
I know that is "stupid polling" but it works absolut perfekt on very fast.
is there a better way?
Post
Replies
Boosts
Views
Activity
I've try to follow your recommend to use NWBrowser but i got only the results "start function" and "end function" with this code
public func findServices() {
print("start function")
let parameter = NWParameters()
parameter.includePeerToPeer = true
let browser = NWBrowser(for: .bonjour(type: "_mesh-http._tcp.", domain: "local."), using: parameter)
browser.stateUpdateHandler = { state in
switch state {
case .ready:
print("the sericeHandler is ready")
case .failed(let error):
print("error:", error.localizedDescription)
default:
break
}
}
browser.browseResultsChangedHandler = { result, changed in
print("in handler")
result.forEach { device in
device.interfaces.forEach {interface in
//ADD THE NAME TO A LIST
print(interface.name)
}
}
changed.forEach{change in
switch change
{
case .identical:
print("no change")
break
case .added:
print("A new result was discovered. ")
case .removed:
print("A previously discovered result was removed.")
default:
break
}
}
}
print("end function")
browser.start(queue: .main)
}
now my Solution. Please leave feedback
--> it's a combination of some answers in this forum
private func findService(with name:String) {
let service = NetService(domain: "local.", type: "_mesh-http._tcp.", name: name)
print("will resolve, service: \(service)")
BonjourResolver.resolve(service: service) { result in
switch result {
case .success(let hostName):
print("did resolve, host: \(hostName)")
case .failure(let error):
print("did not resolve, error: \(error)")
}
}
}
public func findServices()
{
let agent = BrowserAgent()
let browser = NetServiceBrowser()
browser.delegate = agent
browser.searchForServices(ofType: "_mesh-http._tcp.", inDomain: "local.")
browser.schedule(in: RunLoop.main, forMode: .common)
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) { // give the browser time to brows
print("finish")
for device in agent.getDevices(){
print(device)
self.findService(with: device)
}
}
RunLoop.main.run()
}
final class BonjourResolver: NSObject, NetServiceDelegate {
typealias CompletionHandler = (Result<(String, Int), Error>) -> Void
@discardableResult
static func resolve(service: NetService, completionHandler: @escaping CompletionHandler) -> BonjourResolver {
precondition(Thread.isMainThread)
let resolver = BonjourResolver(service: service, completionHandler: completionHandler)
resolver.start()
return resolver
}
private init(service: NetService, completionHandler: @escaping CompletionHandler) {
// We want our own copy of the service because we’re going to set a
// delegate on it but `NetService` does not conform to `NSCopying` so
// instead we create a copy by copying each property.
let copy = NetService(domain: service.domain, type: service.type, name: service.name)
self.service = copy
self.completionHandler = completionHandler
}
deinit {
assert(self.service == nil)
assert(self.completionHandler == nil)
assert(self.selfRetain == nil)
}
private var service: NetService? = nil
private var completionHandler: (CompletionHandler)? = nil
private var selfRetain: BonjourResolver? = nil
private func start() {
precondition(Thread.isMainThread)
guard let service = self.service else { fatalError() }
service.delegate = self
service.resolve(withTimeout: 3.0)
selfRetain = self
}
func stop() {
self.stop(with: .failure(CocoaError(.userCancelled)))
}
private func stop(with result: Result<(String, Int), Error>) {
precondition(Thread.isMainThread)
self.service?.delegate = nil
self.service?.stop()
self.service = nil
let completionHandler = self.completionHandler
self.completionHandler = nil
completionHandler?(result)
selfRetain = nil
}
func netServiceDidResolveAddress(_ sender: NetService) {
let hostName = sender.hostName!
let port = sender.port
if let data = sender.txtRecordData() {
let dict = NetService.dictionary(fromTXTRecord: data)
print(dict.mapValues { String(data: $0, encoding: .utf8) })
}
print("\(hostName) \(port)")
self.stop(with: .success((hostName, port)))
}
func netService(_ sender: NetService, didNotResolve errorDict: [String: NSNumber]) {
let code = (errorDict[NetService.errorCode]?.intValue)
.flatMap { NetService.ErrorCode.init(rawValue: $0) }
?? .unknownError
let error = NSError(domain: NetService.errorDomain, code: code.rawValue, userInfo: nil)
self.stop(with: .failure(error))
}
}
class ServiceAgent : NSObject, NetServiceDelegate {
func netServiceDidResolveAddress(_ sender: NetService) {
if let data = sender.txtRecordData() {
let dict = NetService.dictionary(fromTXTRecord: data)
print("Resolved: \(dict)")
print(dict.mapValues { String(data: $0, encoding: .utf8) })
}
}
}
class BrowserAgent : NSObject, NetServiceBrowserDelegate {
var currentService:NetService?
let serviceAgent = ServiceAgent()
var devices = [String]()
public func getDevices() -> [String]{
return devices
}
func netServiceBrowser(_ browser: NetServiceBrowser, didFindDomain domainString: String, moreComing: Bool) {
print("domain found: \(domainString)")
}
func netServiceBrowser(_ browser: NetServiceBrowser, didFind service: NetService, moreComing: Bool) {
print("service found: \(service.name)")
devices.append(service.name)
}
}
I make the double search because the result of func netServiceBrowser have no Mac address in the NetService-Object(it's always empty) and I need this.
the Solution works but I think it's very awkward
thank you for the fast answer. I think you didn't understand me correctly. :-) i have some devices, but all have the same serviceType and name:
let service = NetService(domain: "local.", type: "_ssh._tcp", name: "mesh")
my problem is that your code find only one device of them. if I switch the founded device off, I can find the next but I need them all I hope my explanation is understandable
Hello, I work with @eskimo code and it runs perfect, but I have one problem.
In my local network are more devices and I find only one of them.
Or do I get all of them and only one device is issued with
switch result {
case .success(let hostName):
print("did resolve, host: \(hostName)")
?
how I get the other one too?
--> at the end, I would like to add them to a List for using later