Thanks for being a part of WWDC25!

How did we do? We’d love to know your thoughts on this year’s conference. Take the survey here

Connecting to a service found by Bonjour isn't working.

I'm using NWBrowser to search for a server that I hosted. The browser does find my service but when it tries to connect to it, it gets stuck in the preparing phase in NWConnection.stateUpdateHandler. When I hardcode the local IP address of my computer (where the server is hosted) into NWConnection it works perfectly fine and is able to connect.

When it gets stuck in the preparing phase, it gives me the warnings and error messages in the image below. You can also see that the service name is correct and it is found.

I have tried _http._tcp and _ssh._tcp types and neither work.

This is what my code looks like:

func findServerAndConnect(port: UInt16) {
    print("Searching for server...")
    let browser = NWBrowser(for: .bonjour(type: "_ssh._tcp", domain: "local."), using: .tcp)
    
    browser.browseResultsChangedHandler = { results, _ in
        print("Found results: \(results)")
        for result in results {
            if case let NWEndpoint.service(name, type_, domain, interface) = result.endpoint {
                if name == "PocketPadServer" {
                    print("Found service: \(name) of type \(type_) in domain \(domain) on interface \(interface)")
                    
                    // Construct the full service name, including type and domain
                    let fullServiceName = "\(name).\(type_).\(domain)"
                    print("Full service name: \(fullServiceName), \(result.endpoint)")
                    
                    self.connect(to: result.endpoint, port: port)
                    browser.cancel()
                    break
                }
            }
        }
    }
    
    browser.start(queue: .main)
}

func connect(to endpoint: NWEndpoint, port: UInt16) {
    print("Connecting to \(endpoint) on port \(port)...")
    
//        endpoint = NWEndpoint(
    
    let tcpParams = NWProtocolTCP.Options()
    tcpParams.enableFastOpen = true
    tcpParams.keepaliveIdle = 2
    let params = NWParameters(tls: nil, tcp: tcpParams)
    params.includePeerToPeer = true
    
    
//        connection = NWConnection(host: NWEndpoint.Host("xx.xxx.xxx.xxx"), port: NWEndpoint.Port(3000), using: params)
    connection = NWConnection(to: endpoint, using: params)
    
    
    connection?.pathUpdateHandler = { path in
        print("Connection path update: \(path)")
        if path.status == .satisfied {
            print("Connection path is satisfied")
        } else {
            print("Connection path is not satisfied: \(path.status)")
        }
    }
    
    connection?.stateUpdateHandler = { newState in
        DispatchQueue.main.async {
            switch newState {
            case .ready:
                print("Connected to server")
                self.pairing = true
                self.receiveMessage()
            case .failed(let error):
                print("Connection failed: \(error)")
                self.isConnected = false
            case .waiting(let error):
                print("Waiting for connection... \(error)")
                self.isConnected = false
            case .cancelled:
                print("Connection cancelled")
                self.isConnected = false
            case .preparing:
                print("Preparing connection...")
                self.isConnected = false
            default:
                print("Connection state changed: \(newState)")
                break
            }
        }
    }
    connection?.start(queue: .main)
}

What platform is this code running on?

I'm using NWBrowser to search for a server that I hosted.

Can you expand on the server in play here? Is it running on your Mac? Or on an Apple device? Or somewhere else?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

@DTS Engineer I am planning to run the server on both Windows and my MacBook. However, I've only tested connections on the MacBook so far. It is set up in Python with asyncio and zeroconf as such.

async def register_service(self):
    self.zeroconf = AsyncZeroconf()
    self.service_info = AsyncServiceInfo(
        "_ssh._tcp.local.",
        f"PocketPadServer._ssh._tcp.local.",
        addresses=[socket.inet_aton(self.host)],
        port=self.port
    )
    await self.zeroconf.async_register_service(self.service_info)

async def start(self):
    await self.register_service()

    self.server = await asyncio.start_server(self.handle_client, self.host, self.port)
    addr = self.server.sockets[0].getsockname()
    logger.info(f"Server running on {addr}")

    async with self.server:
        await self.server.serve_forever()

And are you running the client on that same Mac? Or another machine on the same network?

I’m not a Python expert but I’m concerned about this:

addresses=[socket.inet_aton(self.host)],

In most cases it’s a mistake to listen on a specific IP address. Rather, you should listen on the ‘any’ address. In the BSD Sockets API that’s INADDR_ANY for IPv4 and in6addr_any for IPv6.

And, of course, you want to be listening on both, especially when working with Bonjour, because Bonjour works with link-local addressing and that works much better on IPv6.

As to your main problem, I think it’s important that you tease apart the client and the server code. In this case that’s easy:

  • You can test your client code against the Mac’s built-in SSH server.

  • You can test your server code using Terminal’s built-in Bonjour browser.

To start out, enable SSH on your Mac and try connecting to it from your app. Does that work?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I am running the client on my iPhone. Also, doing _ssh._tcp was done because _http._tcp hadn't been working and I forgot to change it back to _ssh. I'm not trying to use ssh here. I'm no expert at this networking stuff, am I confused about how these types work?

I can see the server when I run dns-sd -B _http._tcp in the terminal on the same mac.

I read somewhere that I might have to set up two protocols depending on ipv4 and ipv6... Is that something I need to do? Which one would iOS be looking at?

Connecting to a service found by Bonjour isn't working.
 
 
Q