2012-11-23 22 views
8

Desidero connettermi a pool.ntp.org per sincronizzare l'ora. Così sono la creazione di un socketIOS che riceve il timeout dei dati CFsocket

sock=CFSocketCreate(NULL, PF_INET, SOCK_DGRAM, IPPROTO_UDP, kCFSocketDataCallBack|kCFSocketWriteCallBack|kCFSocketConnectCallBack, sockCallback, &sock_ctx); 

poi sono la creazione di un ciclo

sockref=CFSocketCreateRunLoopSource(NULL, sock, 0); 
CFRunLoopAddSource(CFRunLoopGetMain(), sockref, kCFRunLoopCommonModes); 

e il collegamento all'indirizzo

CFDataRef adrref=CFDataCreate(NULL, (const UInt8 *)&adr, sizeof(adr)); 
    CFSocketError err=CFSocketConnectToAddress(sock, adrref,-1); 

se ho richiamata kCFSocketWriteCallBack i inviare i dati richiesti

 CFDataRef bufref=CFDataCreate(NULL, buffer, scl->NTP_PACKET_SIZE); 
    CFSocketError error = CFSocketSendData(scl->sock, NULL, bufref,3); 

tutto fino a qui funziona perfettamente.Il mio vero problema è a

else if(callbackType==kCFSocketDataCallBack) 

9/10 volte funziona ok. server che invia la risposta e il mio processo continua. il problema è che sto aspettando che i dati giungano effettivamente alla logica della mia app. se nessun dato arriva kCFSocketDataCallBack non viene attivato e l'app attende per sempre. C'è un modo per mettere un timeout in attesa di ricevere dati? (Senza avere da solo un NSTimer per riconnettersi al pool)

+0

Incontro lo stesso problema, trovi qualche soluzione? – xjdrew

risposta

1

Penso che la cosa importante da sapere qui è che UDP è intrinsecamente inaffidabile.

È quindi assolutamente possibile e normale che i pacchetti vengano persi e che a volte non si ottenga una risposta. Hai menzionato 9 volte su 10, funziona abbastanza bene per un protocollo basato su UDP.

Quindi penso che sia davvero necessario rendere il tuo codice un po 'più intelligente. Penso anche che non ci sia modo di usare un timer per scoprire se hai effettivamente ricevuto una risposta entro una certa quantità di tempo.

Fortunatamente è molto facile programmare uno CFRunLoopTimer nel proprio ciclo. Quello che dovete fare è questo:

  1. Quando si chiama CFSocketSendData per la prima volta anche aggiungere un CFRunLoopTimer.
  2. Quando si riceve una richiamata kCFSocketDataCallBack si annulla il timer
  3. Se non si riceve mai una risposta, o se la risposta arriva molto tardi, il timer si attiva. Così si può semplicemente inviare il pacchetto di nuovo dal tempo del timer di callback e pianificare di nuovo con CFRunLoopTimerSetNextFireDate

È possibile mantenere un contatore in giro che si incrementa ogni volta che si invia un pacchetto. Quindi puoi rinunciare dopo un certo numero di tentativi.

Questo è un po 'più codice ma renderà la tua app basata su UDP molto più affidabile.