Tengo un método UDP que espera una respuesta usando DispatchQueue usando el siguiente código:
DispatchQueue.global(qos: .userInitiated).async { let server:UDPServer=UDPServer(address:"0.0.0.0", port:5005) let (data,_,_) = server.recv(1024) DispatchQueue.main.async { ... } }Esto funciona perfectamente y activa un proceso para esperar a que ingresen mis datos. Lo que me mantiene despierto por la noche es lo que sucede si nunca recibimos una respuesta. server.recv nunca regresa, así que no puedo ver cómo terminará el proceso. ¿Hay alguna manera de darle una cantidad predeterminada de tiempo para ejecutar?
No hay forma de detener o "matar" un DispatchWorkItem o NSOperation desde el exterior. Hay un método cancel() , pero eso simplemente establece la propiedad isCancelled del elemento o la operación en verdadero. Esto no detiene la ejecución del elemento en sí. Respuesta: dado que recv está bloqueando, no hay forma de verificar el indicador isCancelled durante la ejecución. Esto significa que la respuesta publicada por Vadian lamentablemente no haría nada.
De acuerdo con los documentos de Apple en NSOperation.cancel :
Este método no fuerza la detención de su código de operación.
Lo mismo ocurre con NSOperationQueue.cancelAllOperations :
Cancelar las operaciones no las elimina automáticamente de la cola ni detiene las que se están ejecutando actualmente.
Podrías pensar que es posible usar un NSThread sin procesar. Sin embargo, el mismo principio se aplica aquí. No se puede matar de forma determinista un subproceso desde el exterior.
POSIBLE SOLUCIÓN: tiempo de espera
La mejor solución que se me ocurre es usar la función de tiempo de espera del zócalo. No sé de dónde viene UDPServer , pero quizás tenga un tiempo de espera incorporado.
Posible solución: tiempo de espera del pobre (enviar paquete a localhost)
Otra opción que puede probar es enviarse algunos paquetes UDP después de que haya transcurrido cierto tiempo. De esta manera, recv recibirá algunos datos y la ejecución continuará. Esto posiblemente podría usarse como un "tiempo muerto para los pobres".
Agregue un temporizador que se activa después de un intervalo de tiempo de espera específico
Declare una constante para el intervalo de tiempo de espera y una propiedad para el temporizador
private let timeoutSeconds = 30 private var timer : DispatchSourceTimer?y escriba dos funciones para iniciar y detener el temporizador.
fileprivate func startDispatchTimer() { let interval : DispatchTime = .now() + .seconds(timeoutSeconds) if timer == nil { timer = DispatchSource.makeTimerSource(queue: DispatchQueue.global()) timer!.schedule(deadline:interval) timer!.setEventHandler { // do something when the timer fires self.timer = nil } timer!.resume() } } fileprivate func stopDispatchTimer() { timer?.cancel() timer = nil } Inicie el temporizador después de inicializar la instancia del servidor y deténgalo si tiene éxito. En caso de falla, agregue código en el cierre setEventHandler para manejar el tiempo de espera, por ejemplo, desasignar la instancia del servidor.
Donde no debería haber ningún caso en el que UDPServer no regrese. Debe haber un límite de tiempo de espera para el tiempo que UDPServer debe esperar. Por ejemplo, considere el siguiente caso:
DispatchQueue.global(qos: .background).async { let server = UDPServer(address:"0.0.0.0", port:5005) switch server.recv(1024) { case .success: print("Server received message from client.") case .failure(let error): print("Server failed to received message from client: \(error)") } server.close() DispatchQueue.main.async { ... } }