I'm at a bit of a dead-end here and hope someone can shed some light.
Recently refactored a macOS app that sends and receives data on a wired LAN to use Network Framework, and through some stumbling around I've gotten UDP receive (NWListener) working great.
Here's my issue: NWConnection acting as a UDP client (send-only) is working great seemingly -- but once the network connection is lost and returns (ie: unplug the Ethernet cable and plug it back in, or any other condition that would cause connectivity to be lost), the NWConnection simply stops sending messages altogether until I quit and restart my app.
As soon as connectivity is lost and my app tries to send a UDP message, I see these errors in the console:
- [] nw_socket_service_writes_block_invoke [C1:1] sendmsg(fd 7, 28 bytes) [49: Can't assign requested address]
- [] nw_endpoint_flow_prepare_output_frames Failing the write requests [49: Can't assign requested address]
And apparently it is not able to recover after that.
I've checked the documentation, Googled and tried everything I can think of trial-and-error wise and I'm coming up dry.
Through all of it, the state never leaves "ready," but the viability does come and go as the network link goes down and up again as you'd epect.
From what I've read, this sort of connectivity issue should remedy/resolve itself within Network Framework and I shouldn't have to manually deal with it. But if I do, how would I go about it?
I've checked all the connection parameters, context meta data, etc. Really not sure what I'm doing wrong.
Thanks!
public class UDPClient {
public final let name: String
internal final var gcdThread: DispatchQueue = DispatchQueue.main // placeholder; custom thread will be created at class init
internal final func makegcdThread() {
gcdThread = DispatchQueue(label: specifics.app.bundleID + ".udpclient." + name)
}
private var connection: NWConnection?
private var parameters: NWParameters!
private var context: NWConnection.ContentContext?
public internal(set) var host: NWEndpoint.Host
public internal(set) var port: NWEndpoint.Port
public init(name: String, host: NWEndpoint.Host, port: NWEndpoint.Port = 0, parameters: NWParameters? = nil, context: NWConnection.ContentContext? = nil) {
self.name = name
// cache address & port
self.host = host
self.port = port
self.context = context
makegcdThread()
// port params
let params: NWParameters
if parameters != nil {
// user parameers used
params = parameters!
} else {
// default parameters used
params = NWParameters.udp
params.allowLocalEndpointReuse = true
params.includePeerToPeer = true
}
self.parameters = params
// set up connection
connect()
}
internal final func connect() {
// new connection
connection = NWConnection(host: host, port: port, using: self.parameters)
// update handler
connection?.stateUpdateHandler = { [weak self] state in
// state seems to never change and is always in "ready" state for a UDP client...?
self?.stateDidChange(to: state)
}
connection?.viabilityUpdateHandler = { [weak self] isViable in
self?.viabilityDidChange(to: isViable)
}
// start connection
connection?.start(queue: gcdThread)
}
}