Posts

Post marked as solved
2 Replies
2.2k Views
I'm struggling to use NWListener and NWConnection on the same port.I have a simple task requires that I send out a UDP datagram to the broadcast address, and expect to receive replies on the port which sent the datagram. In Blue Sockets, I can create a socket, send out the broadcast message and listen and accept connections on the same socket.In wireshark the exchange looks like:10.0.0.123 255.255.255.255 UDP 71 62003 -> 9000 Len=29 10.0.0.202 10.0.0.123 UDP 1060 9000 -> 62003 Len=101However after hours of experimentation in a swift playground, I am not able to create an NWListener and an NWConnection on the same socket.Here are the salient pieces of code:let udpListener = try! NWListener(using: .udp) ... setup and start listener let broadcast: NWEndpoint.Host = "255.255.255.255" let portUDP: NWEndpoint.Port = 9000 let localPort : NWEndpoint.Port = udpListener!.port! let localEndpoint = NWEndpoint.hostPort(host: "10.0.0.123", port: localPort) let parameters = NWParameters.udp parameters.requiredLocalEndpoint = localEndpoint let connection = NWConnection(host: broadcast, port: portUDP, using: parameters)However creating the NWConnection on the same port as the NWListener gives an error that the port is in use. I've tried the reverse, createing the connection on a known port, closing it and starting a listener immediately affterwards on that same port, but that also results in an error.How can I implement this very simple protocol using the Network API ? Are there some options I need to set ?Thanks for any help.Guy
Posted
by GeeBee2.
Last updated
.
Post not yet marked as solved
2 Replies
426 Views
The following NWConnection code sending a UDP broadcast message works perfectly on Catalina, but fails with EACESS on Mojave. I am guessing that the socket broadcast flag is set on Catalina but not Mojave, is there a workaround to get this function on 10.14, or is broadcast in the Network framework broken in Mojave ?import Network import PlaygroundSupport PlaygroundPage.current.needsIndefiniteExecution = true var broadcastConnection: NWConnection? func broadcast() { let hostUDP: NWEndpoint.Host = "255.255.255.255" let portUDP: NWEndpoint.Port = 9000 broadcastConnection = NWConnection(host: hostUDP, port: portUDP, using: .udp) broadcastConnection?.stateUpdateHandler = { (newState) in switch newState { case .ready: let packet = "Hello".data(using: .utf8)! print("SEND ") broadcastConnection?.send(content: packet, completion: NWConnection.SendCompletion.contentProcessed(({ (NWError) in print("Sent: \(NWError?.debugDescription ?? "Success")") broadcastConnection?.cancel() broadcastConnection = nil PlaygroundPage.current.finishExecution() }))) default: break } } broadcastConnection?.start(queue: .global()) } broadcast()Result on Catalina:SEND Sent: SuccessResult on Mojave:SEND Sent: POSIXErrorCode: Permission deniedThanks for any insight CheersGuy
Posted
by GeeBee2.
Last updated
.
Post marked as solved
3 Replies
1.8k Views
When creating an NWConnectionn on a specific local port, the local IP address also needs to be specified. However there does not seem to be any clean API for discovering what the default NWConnection IP address will be.In fact getting the main local IP address on macOS or iOS does not seem to be straightforward at all.I found a workaround which scarily relies on the debug description for a network connection. Is there a better, more robust way, more in line with the Network API ?import Network import PlaygroundSupport class IPHelper { static var dummy: NWConnection? static func getIPThen(callOnMain: @escaping (NWEndpoint.Host) -> Void ) { guard dummy == nil else { return } dummy = NWConnection(host: "255.255.255.255", port: 9000, using:.udp) dummy?.stateUpdateHandler = {(newState) in switch (newState) { case .ready: let ip = self.dummy?.currentPath?.localEndpoint?.debugDescription.split(separator: ":").first self.dummy?.cancel() self.dummy = nil DispatchQueue.main.async { callOnMain(NWEndpoint.Host("\(ip ?? "")")) } default: break } } dummy?.start(queue: .global()) } } PlaygroundPage.current.needsIndefiniteExecution = true IPHelper.getIPThen { (ip) in let address = ip }
Posted
by GeeBee2.
Last updated
.