2010-03-14 18 views
10

Sto provando a verificare un socket chiuso che è stato chiuso con grazia dal peer senza incorrere nel colpo di latenza di una doppia mandata per indurre uno SIGPIPE.Test per una presa chiusa

Uno dei presupposti qui è che il socket in caso di chiusura è stato chiuso con grazia dal peer subito dopo l'ultima scrittura/invio. Gli errori reali come una chiusura prematura vengono trattati altrove nel codice.

Se il socket è ancora aperto, ci saranno 0 o più dati byte che non voglio ancora estrarre dal buffer socket.

Stavo pensando che potrei chiamare int ret = recv(sockfd, buf, 1, MSG_DONTWAIT | MSG_PEEK); per determinare se il socket è ancora connesso. Se è collegato ma non ci sono dati nel buffer, ricevo un ritorno di -1 con errno == EAGAIN e restituisco il sockfd per il riutilizzo. Se è stato chiuso con grazia dal peer, otterrò ret == 0 e aprirò una nuova connessione.

Ho provato questo e si sembra al lavoro. Tuttavia, ho il sospetto che ci sia una piccola finestra tra quando ricevo l'ultimo bit dei miei dati e quando arriva il peer FIN in cui posso ottenere un falso positivo EAGAIN dal mio test recv.

Questo mi morde o esiste un modo migliore per farlo?

+0

Un modo alternativo è select() (o poll()), dal momento che può controllare un fd sia per leggere che per scrivere, ma non so se effettivamente risolve il problema relativo alla temporizzazione FIN. –

+0

@Giuseppe: No, non penso che la selezione risolverebbe il problema dei tempi. –

risposta

3

OK, così mi sono imbattuto qualche altro test e questo è quello che ho trovato.

Ho impostato il client per inviare i messaggi HTTP/1.1 Connection: close al server, provocando la chiamata del server dopo l'ultima scrittura dei dati. Quando il mio cliente ha finito di leggere i dati da una transazione GET, testava il socket per vedere se era ancora aperto usando il metodo sopra e quindi tentava di emettere un altro GET.

Quello che ho trovato è che circa il 30% delle volte il mio test si sarebbe verificato prima che il server FIN arrivasse a causare falsi positivi e operazioni fallite.

Probabilmente l'unico modo per fare questo ragionevolmente affidabili, dicono vicino al 99% sarebbe quello di introdurre ritardi artificiali legate alla latenza della connessione tra l'ultima lettura e il riutilizzo presa tentato - tuttavia, che sarebbe praticamente prestazioni omicidio.

Quindi, devo concludere che mentre questo strumento è utile, lo è solo marginalmente.

+1

+1: test interessanti. Si può capire perché nel settore delle telecomunicazioni il 90% del codice è destinato alla gestione di comportamenti eccezionali :) – neuro

0

Sei tu che controlli l'altra estremità? Il modo più affidabile per eseguire uno spegnimento "pulito" di un socket è che l'altro capo invii un messaggio di "addio" di qualche tipo.

+1

No, non controllo l'altra estremità. Tuttavia, l'altra estremità ** dovrebbe ** inviare sempre un messaggio a livello di applicazione che indica che stanno chiudendo dalla loro fine. È solo che nel mondo reale ciò non accade sempre.Potrei trattarlo come un errore normale, ma mi piacerebbe provare a prenderlo attivamente il più delle volte. –

0

(leggermente "fuori tema", mi spiace). Forse this discussion potrebbe esserti utile quattro. Ancora non risponde alla domanda "FIN", ma può aiutarti a reagire in modo più semplice allo spegnimento dei peer mentre il tuo programma sta inviando.

Bye