In diesem Beitrag lege ich die Schritte dar, die notwendig sind, um einen UDP-Listener mit Apples Network Framework zu implementieren. Eine SwiftUI-View wird alle eingehenden UDP-Nachrichten anzeigen. Der gesamte Code ist in einem praktischen Xcode-Playground verfuegbar.

Auf der anderen Seite ist ein UDP-Sender, den ich in diesem vorherigen Beitrag erklaert habe:

Send and Receive UDP Messages with Swift

Dieser Beitrag ist in die folgenden Abschnitte unterteilt:

  • Den Listener erstellen
  • Neue Verbindungen akzeptieren
  • Nachrichten empfangen
  • Den Listener starten
  • Den Listener testen

Ich habe einen Xcode-Playground erstellt, der alle eingehenden Nachrichten in einer SwiftUI-View anzeigt.

https://youtu.be/cd4FLF4XTiE

Er kann hier heruntergeladen werden: UDP Listener in Swift

Den Listener erstellen

Alles basiert auf dem NWListener, der beschrieben wird als

“Ein Objekt, das du verwendest, um auf eingehende Netzwerkverbindungen zu lauschen.”

Lass uns einen instanziieren.

var listener: NWListener?

do {
 listener = try NWListener(using:.udp, on: port)
} catch {
 print("exception upon creating listener")
}

Als Naechstes muss das Verhalten von stateUpdateHandler definiert werden. Es wird folgendermassen beschrieben:

“Ein Handler, der Listener-Statusaktualisierungen empfaengt.”

listener?.stateUpdateHandler = {(newState) in
 switch newState {
 case.ready:
  print("ready")
 default:
  break
 }
}

Neue Verbindungen akzeptieren

Der Listener kann jetzt Statusaktualisierungen verarbeiten, aber der Spass beginnt, wenn eine neue Verbindung startet.

Ein weiterer Handler muss implementiert werden: der newConnectionHandler, den die Dokumentation erklaert als

“Ein Handler, der eingehende Verbindungen empfaengt.”

listener?.newConnectionHandler = {(newConnection) in
 newConnection.stateUpdateHandler = {newState in
  switch newState {
  case.ready:
   print("ready")
  default:
   break
  }
 }
 newConnection.start(queue: DispatchQueue(label: "newconn"))
}

Nachrichten empfangen

Wenn die Verbindung bereit ist, muss ein Handler fuer receiveMessage zugewiesen werden:

“Plant einen einzelnen Empfangs-Completion-Handler fuer eine komplette Nachricht ein, im Gegensatz zu einem Bereich von Bytes.”

connection.receiveMessage { (data, context, isComplete, error) in
 // Decode and continue processing data
}

Den Listener starten

Alles ist vorhanden, um den Listener mit start zu starten. Es wird beschrieben als:

“Registriert sich zum Lauschen und legt die Queue fest, auf der alle Listener-Ereignisse zugestellt werden.”

listener?.start(queue:.main)

Den Listener testen

Mit allem, was laeuft, ist es Zeit, den Code zu testen. Der einfachste Weg ist, das Terminal zu oeffnen und auszufuehren:

echo -n "Hello UDP-World" | nc -4u -w1 -localhost 1024

Fuer diejenigen, die mit der Kommandozeile weniger vertraut sind, biete ich einige Erklaerungen aus den Man-Pages der verwendeten Tools.

Zuerst wird die Nachricht mit echo erstellt.

Was ist echo?

“Das echo-Dienstprogramm schreibt alle angegebenen Operanden, getrennt durch einzelne Leerzeichen ( ') und gefolgt von einem Newline-Zeichen (\n’), auf die Standardausgabe.”

Der -n-Parameter ist dokumentiert als:

“Das abschliessende Newline-Zeichen nicht ausgeben. Dies kann auch erreicht werden, indem \c' am Ende des Strings angehaengt wird, wie es bei iBCS2-kompatiblen Systemen gemacht wird. Beachte, dass diese Option sowie die Wirkung von \c’ in IEEE Std 1003.1-2001 (“POSIX.1”) in der Fassung von Cor. 1-2002 implementierungsdefiniert sind. Anwendungen, die maximale Portabilitaet anstreben, werden dringend ermutigt, printf(1) zu verwenden, um das Newline-Zeichen zu unterdruecken.”

Mit dem Pipe-Operator | wird diese Nachricht an ein anderes Tool weitergeleitet, das sie ueber das Netzwerk sendet: netcat oder nc:

“Das nc (oder netcat)-Dienstprogramm wird fuer fast alles verwendet, was mit TCP oder UDP zu tun hat. Es kann TCP-Verbindungen oeffnen, UDP-Pakete senden, auf beliebigen TCP- und UDP-Ports lauschen, Port-Scanning durchfuehren und sowohl mit IPv4 als auch mit IPv6 umgehen. Anders als telnet(1) laesst sich nc gut skripten und trennt Fehlermeldungen auf die Standardfehlerausgabe, anstatt sie auf die Standardausgabe zu senden, wie telnet(1) es bei einigen macht.”

Die folgenden Parameter werden verwendet:

-4: Erzwingt, dass nc nur IPv4-Adressen verwendet.

-u: UDP statt des Standard-TCP verwenden.

-w timeout: Wenn eine Verbindung und stdin laenger als timeout Sekunden inaktiv sind, wird die Verbindung stillschweigend geschlossen. Das -w-Flag hat keine Auswirkung auf die -l-Option (nc wird mit oder ohne -w fuer immer auf eine Verbindung warten). Der Standard ist kein Timeout.

Fazit

Mit diesem Code solltest du jetzt in der Lage sein, UDP-Nachrichten von jedem Sender zu empfangen und die eingehenden Nachrichten fuer alles zu verarbeiten, was deine App tun muss.

Gerne kannst du mir einen Kaffee ausgeben, wenn dir dieser Beitrag gefallen hat

Ressourcen