What is a good way to use NWConnection.recieve()
to receive data through a UDP socket? All I can think of is a recursive function, but that quickly depletes memory and crashes the app.
p.s. NWConnection.recieveMessage()
is the same as NWConnection.recieve()
but without a limiting range
The documentation says
Schedules a single receive completion handler for a complete message, as opposed to a range of bytes.
Does this mean if I run it once, it will wait until there is something to listen to, then run the completion handler? I tried this, but it's not working. I try this in listen()
.
class UDPConnection {
var connection: NWConnection?
var response: Data
init() {
connection = NWConnection(host: NWEndpoint.Host("192.168.0.32"), port: NWEndpoint.Port(rawValue: 32)!, using: .udp)
response = Data()
}
func begin() {
guard let connection = connection else {
print("Connection not initialized.")
return
}
connection.start(queue: .global())
print("Connection started.")
self.listen()
}
func sendData(_ data: Data) {
//connection = NWConnection(host: NWEndpoint.Host("192.168.0.32"), port: NWEndpoint.Port(rawValue: 32)!, using: .udp)
//self.begin()
guard let connection = connection else {
print("Connection not initialized.")
return
}
connection.start(queue: .global())
connection.send(content: data, completion: .contentProcessed { sendError in
if let error = sendError {
print("Failed to send data: \(error)")
} else {
print("Data sent successfully")
}
})
// DispatchQueue.global().asyncAfter(deadline: .now() + 1.0) {
// self.closeConnection()
// print("Connection closed via `DispatchQueue`")
// }
}
func listen() {
guard let connection = connection else {
print("Connection not initialized.")
return
}
if connection.state == .ready {
connection.receiveMessage { (data, _, _, error) in
print("here2")
if let error = error {
print("Error receiving data: \(error)")
return
}
print("Data received successfully")
self.response = data ?? Data([0x65])
print(self.response)
self.listen()
}
print("here")
} else {
print("Connection not ready to receive data.")
DispatchQueue.global().asyncAfter(deadline: .now() + 0.1) {self.listen()}
}
}
func closeConnection() {
guard let connection = connection else {
print("Connection not initialized.")
return
}
connection.cancel()
print("Connection closed.")
}
}
Also, if it helps, I get some warnings in the console:
Error creating the CFMessagePort needed to communicate with PPT.
at the start,
nw_connection_set_queue_block_invoke [C1] Error in client: nw_connection_set_queue called after nw_connection_start
Once before I receive the first piece of data, and
nw_connection_set_queue_block_invoke [C1] Error in client: nw_connection_set_queue called after nw_connection_start, backtrace limit exceeded
before every proceeding piece of data.
To initialize the listener, you must create a listener with NWListener
, assign NWListener.newConnectionHandler
a function containing something to handle the data, and start it using NWListener.start(queue: .global())
. Make sure to pass the connection
closure parameter to the function so it can receive the data correctly.
do {listener = try NWListener(using: .udp, on: listenPort)}
catch {
print("Failed to create listener: \(error)")
return
}
listener?.newConnectionHandler = { [weak self] connection in
self?.receive(connection)
}
listener?.start(queue: .global())
print("Listener started.")
Then, in the receive()
function, use connection.receiveMessage()
to read the data. connection.receive()
can be used to break up the data into separate packets, so recursively run the function to handle the whole message.
func receive(_ connection: NWConnection) {
connection.start(queue: .global())
connection.receiveMessage { [weak self] data, context, isComplete, error in
if let error = error {
print("Error receiving data: \(error)")
return
}
if let data = data {
print("Recieved \(data).")
self?.response = data
} else {
print("Recieved 0 bytes (no data).")
}
if isComplete {
print("Message reception complete. Listening for more messages...")
self?.receive(connection)
}
}
}
If you don't know what [weak self]
is, I recommend this video, by Swiftful Thinking on Youtube.
Apple's documentation for some functions used:
NWListener.newConnectionHandler
More related things can be found my scrolling through the sidebar. Close the open NWConnection/NWListener
menu to get a better view of all the categories provided :)