Udp Listener on iOS 14

UDP Listener on iOS 14

I was able to explore this some more and got some help via the apple developer forums, posting an answer here as well for those who are interested.

I ended up using an NWListener to listen for UDP packets, then set up an NWConnection once once I'd received something. I use this NWConnection to read data from the UDP broadcast.

From Quinn "The Eskimo:"

Listening for UDP broadcasts via an NWListener and then using the NWConnection objects it vends (via the new connection handler) to communicate over unicast with the broadcast’s sender is an expected use case.

I encourage anyone reading this to check out our discussion on the Apple Developer Forum as well.

Here is my implementation:

  var udpListener: NWListener?
var udpConnection: NWConnection?
var backgroundQueueUdpListener = DispatchQueue.main

func findUDP() {
let params = NWParameters.udp
udpListener = try? NWListener(using: params, on: 15000)

udpListener?.service = NWListener.Service.init(type: "_appname._udp")

self.udpListener?.stateUpdateHandler = { update in
print("update")
print(update)
switch update {
case .failed:
print("failed")
default:
print("default update")
}
}
self.udpListener?.newConnectionHandler = { connection in
print("connection")
print(connection)
self.createConnection(connection: connection)
self.udpListener?.cancel()
}
udpListener?.start(queue: self.backgroundQueueUdpListener)
}

func createConnection(connection: NWConnection) {
self.udpConnection = connection
self.udpConnection?.stateUpdateHandler = { (newState) in
switch (newState) {
case .ready:
print("ready")
self.send()
self.receive()
case .setup:
print("setup")
case .cancelled:
print("cancelled")
case .preparing:
print("Preparing")
default:
print("waiting or failed")
}
}
self.udpConnection?.start(queue: .global())
}

func endConnection() {
self.udpConnection?.cancel()
}

UDP Connection failed - Error No route to host since the new iOS Update 14.5.1

I found out you have to request the Multicast Networking Entitlement from Apple:
https://developer.apple.com/contact/request/networking-multicast

Since iOS 14.5 you have to request to use UDP...

If they give you the permission to use it, just follow these steps explained here:
https://developer.apple.com/forums/thread/663271

They usually answer after 1-2 days.

How to work with UDP sockets in iOS, swift?

This solution work for me! Thanks @Paulw11

Swift 4, XCode 10.1, iOS 12.0

Simple connect to the public UDP server (This is NOT optimal version but works):

import UIKit
import Network

class ViewController: UIViewController {

var connection: NWConnection?
var hostUDP: NWEndpoint.Host = "iperf.volia.net"
var portUDP: NWEndpoint.Port = 5201

override func viewDidLoad() {
super.viewDidLoad()

// Hack to wait until everything is set up
var x = 0
while(x<1000000000) {
x+=1
}
connectToUDP(hostUDP,portUDP)
}

func connectToUDP(_ hostUDP: NWEndpoint.Host, _ portUDP: NWEndpoint.Port) {
// Transmited message:
let messageToUDP = "Test message"

self.connection = NWConnection(host: hostUDP, port: portUDP, using: .udp)

self.connection?.stateUpdateHandler = { (newState) in
print("This is stateUpdateHandler:")
switch (newState) {
case .ready:
print("State: Ready\n")
self.sendUDP(messageToUDP)
self.receiveUDP()
case .setup:
print("State: Setup\n")
case .cancelled:
print("State: Cancelled\n")
case .preparing:
print("State: Preparing\n")
default:
print("ERROR! State not defined!\n")
}
}

self.connection?.start(queue: .global())
}

func sendUDP(_ content: Data) {
self.connection?.send(content: content, completion: NWConnection.SendCompletion.contentProcessed(({ (NWError) in
if (NWError == nil) {
print("Data was sent to UDP")
} else {
print("ERROR! Error when data (Type: Data) sending. NWError: \n \(NWError!)")
}
})))
}

func sendUDP(_ content: String) {
let contentToSendUDP = content.data(using: String.Encoding.utf8)
self.connection?.send(content: contentToSendUDP, completion: NWConnection.SendCompletion.contentProcessed(({ (NWError) in
if (NWError == nil) {
print("Data was sent to UDP")
} else {
print("ERROR! Error when data (Type: Data) sending. NWError: \n \(NWError!)")
}
})))
}

func receiveUDP() {
self.connection?.receiveMessage { (data, context, isComplete, error) in
if (isComplete) {
print("Receive is complete")
if (data != nil) {
let backToString = String(decoding: data!, as: UTF8.self)
print("Received message: \(backToString)")
} else {
print("Data == nil")
}
}
}
}
}

Swift UDP Connection Issue

In your function receive you are using the NWConnection.receiveMessage if you check the documentation here:

https://developer.apple.com/documentation/network/nwconnection/3020638-receivemessage

You'll see that it schedules a single receive completion handler. That means that you'll have to do something to trigger it again. What I normally do is have a function like:

private func setupReceive() {
connection.receive(minimumIncompleteLength: 1, maximumLength: MTU) { (data, _, isComplete, error) in
if let data = data, !data.isEmpty {
let message = String(data: data, encoding: .utf8)
print("connection \(self.id) did receive, data: \(data as NSData) string: \(message ?? "-")")
self.send(data: data)
}
if isComplete {
self.connectionDidEnd()
} else if let error = error {
self.connectionDidFail(error: error)
} else {
self.setupReceive() // HERE I SET THE RECEIVE AGAIN
}
}
}

That way, after processing the read, you end up setting up another single receive completion handler.

If you want to see a full example, you can check my article on using Network.framework here:

https://rderik.com/blog/building-a-server-client-aplication-using-apple-s-network-framework/

The example uses TCP instead of UDP, but it should give a general idea.

Flutter/Dart UDP multicast send from iOS not receiving on Android

I ended up using a package called Bonsoir to achieve what I wanted to.
It lets you broadcast and receive network services, and I'm pretty sure its the same underlying technology as household programs like Airplay and Google Casting. It's also very reliable and simple to use.

To send a certain string, I passed in a string argument in the form of a dictionary into the attributes attribute within the BonsoirService class.

The package can be found here.

iPhone UDP broadcast and response

You can use cocoaAsyncSocket which is easier to use than apple native classes.

It support UDP with AsyncUdpSocket class.

AsyncUdpSocket is a UDP/IP socket networking library that wraps
CFSocket. It works almost exactly like the TCP version, but is
designed specifically for UDP. This includes queued non-blocking
send/receive operations, full delegate support, run-loop based,
self-contained class, and support for IPv4 and IPv6



Related Topics



Leave a reply



Submit