iOS 14 上的 UDP 侦听器 [英] UDP Listener on iOS 14

查看:52
本文介绍了iOS 14 上的 UDP 侦听器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个关于如何在 iOS 14 上设置 UDP 侦听器的问题.我有一个过去工作过的 UDP 侦听器,但在更新到 iOS 14 后,它偶尔工作/根本不工作.

它存在于一个 NSObject 中,并在端口 15000(没有特定的 IP 地址)上侦听本地网络上的 UDP 广播.它使用 CocoaAsyncSocket 库.当我调用 setUpSocket() 时,不会触发本地网络权限,但该应用程序能够偶尔获取 UDP 数据包.

<预><代码>var 套接字:GCDAsyncUdpSocket?var 广播端口:UInt16 = 15000var broadcastAddress: String = "";var connectAddress = "";变量连接端口 = 0func setUpSocket() {发现UDP()let socket = GCDAsyncUdpSocket(delegate: self, delegateQueue: DispatchQueue.main)socket.setIPv4Enabled(true)socket.setIPv6Enabled(false)做 {试试 socket.bind(toPort: broadcastPort)/*15000*/尝试 socket.enableBroadcast(false)尝试 socket.beginReceiving()} catch let error as NSError {打印(设置监听器的问题\(错误)")}}/*当收到UDP数据包时调用.*/func udpSocket(_ sock: GCDAsyncUdpSocket, didReceive data: Data, fromAddress: Data, withFilterContext filterContext: Any?) {做 {让 jsonDictionary = 尝试 JSONSerialization.jsonObject(with: data, options: []) as![字符串:任意]如果(连接 == 假){如果(jsonDictionary[地址"] != nil){如果(jsonDictionary[地址"] 是 NSArray){让地址 = jsonDictionary[地址"] 作为!数组对于地址中的 i {让 ipAddress:String = i as!细绳if (ipAddress.range(of: "^([0-9]{1,3}\\.){3}[0-9]{1,3}(\\/([0-9]|[1-2][0-9]|3[0-2]))?$",选项:.regularExpression) != nil) {连接地址 = ipAddress}}connectPort = jsonDictionary[Port"] as!整数}/*在UDP广播中提供的IP和端口上建立TCP连接.*/设置网络通信(ip:connectAddress,端口:connectPort)关闭套接字()}}} 抓住让错误{返回打印(错误)}}

我该如何更新以符合 iOS 14?如果我需要更新以使用 Bonjour 服务,我如何在不指定地址的情况下侦听端口(并且不必查找特定的 Bonjour 服务广播,因为我正在寻找的广播不使用 Bonjour).

快速打开和关闭 Bonjour NWBrowser 以触发网络权限,然后按原样使用我的代码是否可以接受?这似乎有效,但充其量似乎很糟糕.

提前致谢.

解决方案

我能够对此进行更多探索,并通过 Apple 开发者论坛获得了一些帮助,并在此处为感兴趣的人发布了答案.

我最终使用了一个 NWListener 来监听 UDP 数据包,然后在我收到一些东西后设置一个 NWConnection.我使用这个 NWConnection 从 UDP 广播中读取数据.

来自奎因《爱斯基摩人》:

<块引用>

通过 NWListener 侦听 UDP 广播,然后使用它提供的 NWConnection 对象(通过 新的连接处理程序) 与广播的发送方通过单播进行通信是预期的用例.

我鼓励任何阅读本文的人查看我们在 Apple 开发者论坛上的讨论 也是.

这是我的实现:

 var udpListener: NWListener?var udpConnection:NWConnection?var backgroundQueueUdpListener = DispatchQueue.mainfunc findUDP() {让参数 = NWParameters.udpudpListener = 试试?NWListener(使用:params,在:15000)udpListener?.service = NWListener.Service.init(类型:_appname._udp")self.udpListener?.stateUpdateHandler = { 更新打印(更新")打印(更新)切换更新{案例.失败:打印(失败")默认:打印(默认更新")}}self.udpListener?.newConnectionHandler = { 连接输入打印(连接")打印(连接)self.createConnection(连接:连接)self.udpListener?.cancel()}udpListener?.start(队列:self.backgroundQueueUdpListener)}func createConnection(连接:NWConnection){self.udpConnection = 连接self.udpConnection?.stateUpdateHandler = { (newState) in开关(新状态){案例 .ready:打印(准备好")self.send()self.receive()案例.setup:打印(设置")案例.取消:打印(取消")案例.准备:打印(准备中")默认:打印(等待或失败")}}self.udpConnection?.start(队列:.global())}功能结束连接(){self.udpConnection?.cancel()}

I have a question regarding how to set up a UDP listener on iOS 14. I have a UDP listener which has worked in the past, but after updating to iOS 14 it works sporadically/not at all.

This lives in an NSObject, and listens for a UDP broadcast across the local network on port 15000 (no specific IP address). It uses the CocoaAsyncSocket library. When I call setUpSocket() local network permissions are not triggered, but the app is able to sporadically pick up UDP packets.


var socket: GCDAsyncUdpSocket?
var broadcastPort: UInt16 = 15000
var broadcastAddress: String = ""
var connectAddress = ""
var connectPort = 0

func setUpSocket() {
    findUDP()
    let socket = GCDAsyncUdpSocket(delegate: self, delegateQueue: DispatchQueue.main)
     
    socket.setIPv4Enabled(true)
    socket.setIPv6Enabled(false)
     
    do {
      try socket.bind(toPort: broadcastPort) /*15000*/
      try socket.enableBroadcast(false)
      try socket.beginReceiving()
       
    } catch let error as NSError {
       
      print("Issue with setting up listener \(error)")
       
    }
     
  }

/*Called when UDP packets are received.*/
func udpSocket(_ sock: GCDAsyncUdpSocket, didReceive data: Data, fromAddress: Data, withFilterContext filterContext: Any?) {
     
    do {
      let jsonDictionary = try JSONSerialization.jsonObject(with: data, options: []) as! [String : Any]
       
      if (connected == false) {
        if (jsonDictionary["Addresses"] != nil) {
          if (jsonDictionary["Addresses"] is NSArray) {
            let addresses = jsonDictionary["Addresses"] as! NSArray
             
            for i in addresses {
              let ipAddress:String = i as! String
              if (ipAddress.range(of: "^([0-9]{1,3}\\.){3}[0-9]{1,3}(\\/([0-9]|[1-2][0-9]|3[0-2]))?$", options: .regularExpression) != nil) {
                connectAddress = ipAddress
              }
            }
            connectPort = jsonDictionary["Port"] as! Int
          }
           
          /*Sets up a TCP connection on the IP and Port provided in the UDP broadcast.*/
          setupNetworkCommunication(ip: connectAddress, port: connectPort)
          
          closeSocket()

        }
      }
       
    } catch let error {
      return print(error)
    }
  }

How can I update this to comply with iOS 14? If I need to update to use Bonjour services, how can I listen on a port without specifying an address (and without having to look for a specific Bonjour service broadcast, because the broadcast I'm looking for doesn't use Bonjour).

Is it acceptable to quickly open and close a Bonjour NWBrowser in order to trigger the network permissions, and then use my code as-is? This seems to work but seems hacky at best.

Thanks in advance.

解决方案

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()
  }

这篇关于iOS 14 上的 UDP 侦听器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆