I've found a handful of other posts that seem to be also not answered regarding the Network framework not receiving messages on UDP channels. @Eskimo, whom I perceive as a legend of the apple forums even posted some nearly identical code about a year and a half ago that he said worked where recent posts comment that they are having the same experience as I am.
What I'm doing:
I want to switch my networking framework to use Network framework's NWConnection. Then I want to send and receive on multiple(3) streams to some non-apple device that I connect to via WiFi with NEHotspotConfigurationManager. This worked before with SwiftSocket and CocoaAsyncSocket.
Problem:
NWConnection.receiveMessage(completion:) doesn't seem to get called by UDP, here is my code.
Any ideas what's missing or wrong?
class UDPClient {
var connection: NWConnection
var address: NWEndpoint.Host
var port: NWEndpoint.Port
var delegate: UDPListener?
private var listening = true
var resultHandler = NWConnection.SendCompletion.contentProcessed { NWError in
guard NWError == nil else {
print("ERROR! Error when data (Type: Data) sending. NWError: \n \(NWError!)")
return
}
}
init?(address newAddress: String, port newPort: Int32, listener isListener: Bool = true) {
guard let codedAddress = IPv4Address(newAddress),
let codedPort = NWEndpoint.Port(rawValue: NWEndpoint.Port.RawValue(newPort)) else {
print("Failed to create connection address")
return nil
}
address = .ipv4(codedAddress)
port = codedPort
listening = isListener
connection = NWConnection(host: address, port: port, using: .udp)
connect()
}
func connect() {
connection.stateUpdateHandler = { newState in
switch (newState) {
case .ready:
print("State: Ready")
if self.listening { self.listen() }
case .setup:
print("State: Setup")
case .cancelled:
print("State: Cancelled")
case .preparing:
print("State: Preparing")
default:
print("ERROR! State not defined!\n")
}
}
connection.start(queue: .global())
}
func send(_ data: Data) {
connection.send(content: data, completion: resultHandler)
}
private func listen() {
while listening {
connection.receiveMessage { data, context, isComplete, error in
print("Receive isComplete: " + isComplete.description)
guard let data = data else {
print("Error: Received nil Data")
return
}
print("Data Received")
}
}
}
}
Once your connection is 'ready' you simply need to call receiveMessage() once.
When a message is available your completion handler will be invoked.
Once you have handled that message you can call receiveMessage() again from your completion handler if you want to receive further messages
As far as I can tell from the code you have posted you are blocking the caller of your state update handler by calling your listen method which is simply sitting in a loop calling receiveMessage() which is probably preventing the 'connection' from doing anything else.