问题描述
我有一个关于如何在 iOS 14 上设置 UDP 侦听器的问题.我有一个过去工作过的 UDP 侦听器,但在更新到 iOS 14 后,它偶尔工作/根本不工作.
它存在于一个 NSObject 中,并在端口 15000(没有特定的 IP 地址)上侦听本地网络上的 UDP 广播.它使用 CocoaAsyncSocket 库.当我调用 setUpSocket()
时,不会触发本地网络权限,但该应用程序能够偶尔获取 UDP 数据包.
我该如何更新以符合 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:"
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 侦听器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!