UDP Broadcasts empfangen

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • UDP Broadcasts empfangen

    Hi,

    ich arbeite an einer App die helfen soll RavenCore HomeKit Geräte zu verwalten. Diese Geräte senden, wenn Sie Updaten oder je nach Config, eine UDP Broadcast auf Port 45678. Diesen kann man z.B. am Mac mit nc -kulnw0 45678 sich anschauen. Genau dies will ich in meine App einbauen, aber ich finde nichts das mir weiter hilft. Ich habe es bisher hinbekommen EINE Nachtricht zu empfangen, aber es scheint so als ob die Funktion die ich gefunden habe, sich beendet wenn eine Nachricht ankam. Ich müsste irgendwie den Stream permanent lesen können, bis man die View verlässt. Hat hier jemand Erfahrungen damit und kann mit mal eine Richtig weisen?

    Zu allem Überfluss muss der Kram in SwiftUI laufen...

    Danke schon mal im voraus

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von Qvex23 ()

  • manoh schrieb:

    Der Port sieht iwie. komisch aus... Aber Okay. Dazu wäre meine Frage, machen die nicht Bonjour, also wenn da HomeKit steht?

    SwiftUI ist nicht für Netzwerk-Programmierung da. Aber es gibt doch ein neues Network Framework. Schon mal da reingeguckt? Oder klassisch mit Socket/Stream/Port.
    Der Port kann alles sein zwischen 1 und 65535, was genau findest du daran komisch? Der Entwickler hat das nun mal auf Port 45678 festgelegt, ist doch auch cool zu merken und vermutlich war der auch "frei genug" so das es mit keinem Standard Port kollidiert. Und ja, die Geräte müssen Bonjour machen, aber das hilft nix, wenn das Gerät während des Updates auf Port 45678 UDP Daten sendet, die ich empfangen möchte.

    Trotzdem danke an alle Antworten, ich werde mir das mal anschauen.

    Ich denke mein größtes Problem wird SwiftUI sein und das man vermutlich für die Funktion ein Delegate setzen muss. Ich habe schon eine Class mit einem Delegate für Bonjour und wenn ich eine weitere Class mache mit einem Delegate knallt es sofort in der App, weil die Delegates anscheinend sich überschreiben.

    Habe für SwiftUI nur folgende Funktion gefunden ein Delegate zu setzen:


    Quellcode

    1. @UIApplicationDelegateAdaptor(DiscoverBonjour.self) var bonjourDelegate
    2. class DiscoverBonjour: NSObject, NetServiceBrowserDelegate, NetServiceDelegate, UIApplicationDelegate {
    3. func startDiscover() {
    4. self.nsb = NetServiceBrowser()
    5. self.nsb.delegate = self
    6. ...
    7. }
    8. ...
    9. }
    Alles anzeigen
    Mache ich das selbe noch mal für den UDP Socken, kommt halt sofort eine Fehlermeldung.
  • Okay, habe es doch hinbekommen und nun kann ich die Daten in der Xcode Console sehen. Nun weiß nur nicht wie dich diese Daten in meine View bringe. Kann mir mal jemand auf die Sprünge helfen?

    Es sieht derzeit so aus:

    Quellcode

    1. class delegates: NSObject, ObservableObject, NetServiceBrowserDelegate, NetServiceDelegate, UIApplicationDelegate, GCDAsyncUdpSocketDelegate {
    2. ...
    3. @Published var logText: String = ""
    4. func connect() {
    5. print("UDP - Connecting Socket")
    6. socket = GCDAsyncUdpSocket(delegate: self, delegateQueue: DispatchQueue.main)
    7. if !socket.isConnected() {
    8. do {try socket.bind(toPort: udpPort)} catch { print("")}
    9. do { try socket.enableBroadcast(true)} catch { print("not able to broad cast")}
    10. do { try socket.beginReceiving()} catch { print("beginReceiving not proceed")}
    11. }
    12. }
    13. func disconnect() {
    14. print("UDP - Closing Socket")
    15. socket.close()
    16. }
    17. func udpSocket(_ sock: GCDAsyncUdpSocket, didReceive data: Data, fromAddress address: Data, withFilterContext filterContext: Any?) {
    18. let msg = String.init(data: data, encoding: String.Encoding.utf8)
    19. print("UDP - \(msg ?? "")")
    20. logText = msg ?? ""
    21. }
    22. }
    Alles anzeigen

    Quellcode

    1. struct LogView: View {
    2. @UIApplicationDelegateAdaptor(MainView.delegates.self) var udp
    3. var body: some View {
    4. Text(udp.logText)
    5. .fontWeight(.light)
    6. .padding()
    7. .onAppear(perform: {
    8. udp.connect()
    9. })
    10. .onDisappear {
    11. udp.disconnect()
    12. }
    13. }
    Alles anzeigen

    Was man hier sieht scheint nicht zu funktionieren. Wie bekomme ich nun die Logmessages in die View?
  • Qvex23 schrieb:

    Der Port kann alles sein zwischen 1 und 65535, was genau findest du daran komisch? Der Entwickler hat das nun mal auf Port 45678 festgelegt, ist doch auch cool zu merken und vermutlich war der auch "frei genug" so das es mit keinem Standard Port kollidiert. Und ja, die Geräte müssen Bonjour machen, aber das hilft nix, wenn das Gerät während des Updates auf Port 45678 UDP Daten sendet, die ich empfangen möchte.
    Hab's gestern selber gesehen, dass dieser Port für das Logging genutzt wird und nix mit Bonjour zu tun hat. Somit kommt das mir auch nicht mehr komisch vor.

    Kann man da vllt. `$udp.logText` schreiben? - Da muss man dem View irgendwie mitteilen, dass das @Published überwacht werden soll, also auf Veränderung reagieren soll.
  • manoh schrieb:

    Qvex23 schrieb:

    Der Port kann alles sein zwischen 1 und 65535, was genau findest du daran komisch? Der Entwickler hat das nun mal auf Port 45678 festgelegt, ist doch auch cool zu merken und vermutlich war der auch "frei genug" so das es mit keinem Standard Port kollidiert. Und ja, die Geräte müssen Bonjour machen, aber das hilft nix, wenn das Gerät während des Updates auf Port 45678 UDP Daten sendet, die ich empfangen möchte.
    Hab's gestern selber gesehen, dass dieser Port für das Logging genutzt wird und nix mit Bonjour zu tun hat. Somit kommt das mir auch nicht mehr komisch vor.
    Kann man da vllt. `$udp.logText` schreiben? - Da muss man dem View irgendwie mitteilen, dass das @Published überwacht werden soll, also auf Veränderung reagieren soll.
    Ich habe nun folgendes zusammengebaut:


    Quellcode

    1. struct LogView: View {
    2. @UIApplicationDelegateAdaptor(Delegates.self) var udp
    3. @ObservedObject var delegates: Delegates
    4. var body: some View {
    5. VStack {
    6. Text("You need to be on the same Network, as the HAA Device, wich sends the logs, or you need to configure your HAA Device to send logs directly to this iOS Device.")
    7. .fontWeight(.thin)
    8. .padding()
    9. Text(delegates.logText)
    10. .fontWeight(.light)
    11. .padding()
    12. .onAppear(perform: {
    13. udp.connect()
    14. })
    15. .onDisappear(perform: {
    16. udp.disconnect()
    17. })
    18. }
    19. }
    20. struct LogView_Previews: PreviewProvider {
    21. static var previews: some View {
    22. LogView(delegates: Delegates())
    23. }
    24. }
    25. }
    26. class Delegates: NSObject, ObservableObject, NetServiceBrowserDelegate, NetServiceDelegate, UIApplicationDelegate, GCDAsyncUdpSocketDelegate {
    27. ...
    28. // MARK: - UDP Socket Stuff
    29. let udpPort:UInt16 = 45678
    30. var socket = GCDAsyncUdpSocket()
    31. @Published var logText:String = ""
    32. func connect() {
    33. print("UDP - Connecting Socket")
    34. socket = GCDAsyncUdpSocket(delegate: self, delegateQueue: DispatchQueue.main)
    35. if !socket.isConnected() {
    36. do {try socket.bind(toPort: udpPort)} catch { print("")}
    37. do { try socket.enableBroadcast(true)} catch { print("not able to broad cast")}
    38. do { try socket.beginReceiving()} catch { print("beginReceiving not proceed")}
    39. }
    40. }
    41. func disconnect() {
    42. print("UDP - Closing Socket")
    43. socket.close()
    44. }
    45. func udpSocket(_ sock: GCDAsyncUdpSocket, didConnectToAddress address: Data) {
    46. print("UDP - Cool, I'm connected! That was easy.")
    47. }
    48. func udpSocket(_ sock: GCDAsyncUdpSocket, didReceive data: Data, fromAddress address: Data, withFilterContext filterContext: Any?) {
    49. logText = String(data: data, encoding: String.Encoding.utf8) ?? "You need to be on the same Network, as the HAA Device, wich sends the logs, or you need to configure your HAA Device to send logs directly to this iOS Device."
    50. print("UDP - \(logText)")
    51. }
    52. }
    Alles anzeigen
    aber leider wird der Text in der View LogView nicht aktualisiert. In der Console kann ich genau sehen, das dort Logdaten durchlaufen.

    Was mache ich denn noch falsch?
  • also geht recht easy. dein ganzer code kommt in eine Klasse...


    class MyCode
    ….. da gibt es eine published var
    @Published var logText:String = ""

    die musst du dann in deiner klasse updaten wie

    logText = „neuer text“

    das sagt dann deiner View, zeichne mich neu

    in deiner View

    struct MyView: View

    sagtst du dann, dass du eine neue Variable haben möchtest

    @StateObject private var myCode = MyCode()

    und dann sagst du im body, dass du es ausgeben möchtest

    Text(myCode.logText)

    das wars.

    jedes mal, wenn du dann logText änderst, wird deine View neu gezeichnet und dein neuer Inhalt ausgegeben.
  • Wolf schrieb:

    also geht recht easy. dein ganzer code kommt in eine Klasse...


    class MyCode
    ….. da gibt es eine published var
    @Published var logText:String = ""

    die musst du dann in deiner klasse updaten wie

    logText = „neuer text“

    das sagt dann deiner View, zeichne mich neu

    in deiner View

    struct MyView: View

    sagtst du dann, dass du eine neue Variable haben möchtest

    @StateObject private var myCode = MyCode()

    und dann sagst du im body, dass du es ausgeben möchtest

    Text(myCode.logText)

    das wars.

    jedes mal, wenn du dann logText änderst, wird deine View neu gezeichnet und dein neuer Inhalt ausgegeben.
    Danke, das funktionierte (zwar auch erst, nach dem ich mein @UIApplicationDelegateAdaptor(Delegates.self) var udp gelöscht habe, weil ich ja kein Delegate in der View brauchte)! Ich hatte statt @StateObject ein @ObservedObject, war das falsch?

    Auf jeden Fall kommen nun Texte in meinen Textview, nun muss ich nur noch schauen wie ich daraus ein Scrollbares Log mache....
  • manoh schrieb:

    Kann man da vllt. `$udp.logText` schreiben?
    Ja kann man. Siehe Beispiel

    Quellcode

    1. import SwiftUI
    2. import Network
    3. class LogBrowser {
    4. private let queue: DispatchQueue
    5. private let listener: NWListener
    6. @Published var text: String = ""
    7. init(queue: DispatchQueue) throws {
    8. self.queue = queue
    9. self.listener = try NWListener(using: .udp, on: 45678)
    10. self.setupHandlers()
    11. }
    12. private func setupHandlers() {
    13. listener.newConnectionHandler = { (conn) -> Void in
    14. conn.receiveMessage() { (data, context, isComplete, error) in
    15. if let error = error {
    16. print("Error: \(error)")
    17. } else if let data = data {
    18. guard let str = String(data: data, encoding: .utf8) else {
    19. print("Failed to parse string!")
    20. return
    21. }
    22. self.text = str
    23. }
    24. }
    25. conn.start(queue: self.queue)
    26. }
    27. }
    28. static func listen(queue: DispatchQueue) -> LogBrowser {
    29. do {
    30. let browser = try LogBrowser(queue: queue)
    31. browser.start()
    32. return browser
    33. } catch {
    34. print("Unexpected error: \(error).")
    35. exit(1)
    36. }
    37. }
    38. func start() {
    39. self.listener.start(queue: self.queue)
    40. }
    41. func cancel() {
    42. self.listener.cancel()
    43. }
    44. }
    45. struct ContentView: View {
    46. @State var logText = ""
    47. let browser: LogBrowser
    48. var body: some View {
    49. Text("\(logText)")
    50. .onReceive(browser.$text, perform: { text in
    51. self.logText += "\(text)\n"
    52. })
    53. .frame(minWidth: 100, idealWidth: 200, maxWidth: .infinity, minHeight: 50, idealHeight: 100, maxHeight: .infinity, alignment: .center)
    54. .padding()
    55. }
    56. }
    57. struct ContentView_Previews: PreviewProvider {
    58. static let browser = LogBrowser.listen(queue: .main)
    59. static var previews: some View {
    60. ContentView(browser: browser)
    61. }
    62. }
    Alles anzeigen