I am trying to create a listener from a drone to my device and receive the data from the from the drone over the UDP connection. The problem is when I start listening to the port where the drone is sending data it only able to read the data once. After that I get some bunch of logs, and I don't know what they are.
I have never implemented a UDP socket in iOS.
My current code
import UIKit
import Network
class ViewController: UIViewController {
private var listener: NWListener?
override func viewDidLoad() {
super.viewDidLoad()
startUDPListener()
}
private func startUDPListener() {
do {
let port: NWEndpoint.Port = 14550
listener = try NWListener(using: .udp, on: port)
listener?.stateUpdateHandler = { state in
switch state {
case .ready:
print("UDP Listener ready on port 14550")
case .failed(let error):
print(" Listener failed:", error)
default:
break
}
}
listener?.newConnectionHandler = { [weak self] connection in
print(" New UDP connection")
self?.receive(on: connection)
connection.start(queue: .main)
}
listener?.start(queue: .main)
} catch {
print(" Failed to start UDP listener:", error)
}
}
private func receive(on connection: NWConnection) {
connection.receiveMessage { [weak self] data, context, isComplete, error in
if let data = data, !data.isEmpty {
print("Received \(data.count) bytes")
// Example: raw bytes
print(data as NSData)
// TODO: Decode MAVLink / custom protocol here
}
if error == nil {
self?.receive(on: connection)
}
}
}
deinit {
listener?.cancel()
}
}
I am getting all these logs but not the data:
UDP Listener ready on port 14550
New UDP connection
Received 40 bytes
nw_path_evaluator_create_flow_inner failed NECP_CLIENT_ACTION_ADD_FLOW (null) evaluator parameters: udp, definite, server, attribution: developer, reuse local address, context: Default Network Context (private), proc: 041A3A9F-1BE2-3236-A958-3B4930D1B4C2, local address: 0.0.0.0:14550
nw_path_evaluator_create_flow_inner NECP_CLIENT_ACTION_ADD_FLOW 464C637F-0893-4191-92AA-B82E76CB684E [17: File exists]
nw_endpoint_flow_setup_channel [C2 192.168.4.1:14550 initial channel-flow (satisfied (Path is satisfied), viable, interface: en0[802.11], ipv4, dns, uses wifi)] failed to request add nexus flow
nw_endpoint_flow_failed_with_error [C2 192.168.4.1:14550 initial channel-flow (satisfied (Path is satisfied), viable, interface: en0[802.11], ipv4, dns, uses wifi)] already failing, returning
nw_endpoint_handler_create_from_protocol_listener [C2 192.168.4.1:14550 failed channel-flow (satisfied (Path is satisfied), viable, interface: en0[802.11], ipv4, dns, uses wifi)] nw_endpoint_flow_pre_attach_protocols
nw_connection_create_from_protocol_on_nw_queue [C2] Failed to create connection from listener
nw_ip_channel_inbox_handle_new_flow nw_connection_create_from_protocol_on_nw_queue failed
{length = 40, bytes = 0xfd1c0000 3f01011e 0000f3cf 1600acb7 ... 38ba98dc 543b049a }
nw_path_evaluator_create_flow_inner failed NECP_CLIENT_ACTION_ADD_FLOW (null) evaluator parameters: udp, definite, server, attribution: developer, reuse local address, context: Default Network Context (private), proc: 041A3A9F-1BE2-3236-A958-3B4930D1B4C2, local address: 0.0.0.0:14550
nw_path_evaluator_create_flow_inner NECP_CLIENT_ACTION_ADD_FLOW 464C637F-0893-4191-92AA-B82E76CB684E [17: File exists]
nw_endpoint_flow_setup_channel [C3 192.168.4.1:14550 initial channel-flow (satisfied (Path is satisfied), viable, interface: en0[802.11], ipv4, dns, uses wifi)] failed to request add nexus flow
nw_endpoint_flow_failed_with_error [C3 192.168.4.1:14550 initial channel-flow (satisfied (Path is satisfied), viable, interface: en0[802.11], ipv4, dns, uses wifi)] already failing, returning
nw_endpoint_handler_create_from_protocol_listener [C3 192.168.4.1:14550 failed channel-flow (satisfied (Path is satisfied), viable, interface: en0[802.11], ipv4, dns, uses wifi)] nw_endpoint_flow_pre_attach_protocols
nw_connection_create_from_protocol_on_nw_queue [C3] Failed to create connection from listener
nw_ip_channel_inbox_handle_new_flow nw_connection_create_from_protocol_on_nw_queue failed
nw_path_evaluator_create_flow_inner failed NECP_CLIENT_ACTION_ADD_FLOW (null) evaluator parameters: udp, definite, server, attribution: developer, reuse local address, context: Default Network Context (private), proc: 041A3A9F-1BE2-3236-A958-3B4930D1B4C2, local address: 0.0.0.0:14550
nw_path_evaluator_create_flow_inner NECP_CLIENT_ACTION_ADD_FLOW 464C637F-0893-4191-92AA-B82E76CB684E [17: File exists]
Hello Every one I have done some research and found a reliable solution regarding this.
As I learn more about UDP I realize in UDP the listning and sending of data can be implemented independently so, below code I have used for contineouslly listning for the data hope this will help out. If needed I can also provide the working code for sending data in UDP. but my question is not abut sending data so for this question I am not adding that.
import Foundation
final class UdpListenerManager {
private var socketFD: Int32 = -1
private var isListening = false
private let queue = DispatchQueue(label: "udp.listener.queue", qos: .background)
private var currentTelemetry = TelemetryData()
private var receiveBuffer = Data()
var onTelemetryUpdate: ((TelemetryData) -> Void)?
var onDataReceived: ((Data, sockaddr_in) -> Void)?
func startListening(on port: UInt16) {
guard !isListening else { return }
isListening = true
queue.async { [weak self] in
self?.setupSocketAndListen(port: port)
}
}
func stopListening() {
isListening = false
if socketFD >= 0 {
close(socketFD)
socketFD = -1
}
}
deinit {
stopListening()
}
private func setupSocketAndListen(port: UInt16) {
socketFD = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
guard socketFD >= 0 else {
print("Failed to create UDP socket")
return
}
var reuse: Int32 = 1
setsockopt(
socketFD,
SOL_SOCKET,
SO_REUSEADDR,
&reuse,
socklen_t(MemoryLayout.size(ofValue: reuse))
)
var addr = sockaddr_in()
addr.sin_family = sa_family_t(AF_INET)
addr.sin_port = port.bigEndian
addr.sin_addr = in_addr(s_addr: INADDR_ANY)
let bindResult = withUnsafePointer(to: &addr) {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
bind(socketFD, $0, socklen_t(MemoryLayout<sockaddr_in>.size))
}
}
guard bindResult == 0 else {
print("Bind failed on port \(port)")
close(socketFD)
socketFD = -1
return
}
print("UDP listening on port \(port)")
receiveLoop()
}
private func receiveLoop() {
while isListening {
var buffer = [UInt8](repeating: 0, count: 2048)
var sourceAddr = sockaddr_in()
var addrLen: socklen_t = socklen_t(MemoryLayout<sockaddr_in>.size)
let receivedBytes = withUnsafeMutablePointer(to: &sourceAddr) {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
recvfrom(
socketFD,
&buffer,
buffer.count,
0,
$0,
&addrLen
)
}
}
guard receivedBytes > 0 else {
if isListening {
print("⚠️ recvfrom failed")
}
continue
}
let data = Data(buffer.prefix(receivedBytes))
// Original raw callback
onDataReceived?(data, sourceAddr)
// Logic to decode and return telemetry data
decodeMavlink(data)
}
}
private func decodeMavlink(_ data: Data) {
//do the decoding of the data according to your need
}
private func bytesToFloat(_ b: [UInt8], _ o: Int) -> Float {
let u = UInt32(b[o]) | (UInt32(b[o+1]) << 8) | (UInt32(b[o+2]) << 16) | (UInt32(b[o+3]) << 24)
return Float(bitPattern: u)
}
}