Non vedendo il tuo codice dovrò indovinare.
Il motivo per cui si ottiene una finestra Zero in TCP è perché non c'è spazio nel buffer di ricezione del ricevitore.
Ci sono diversi modi in cui ciò può accadere. Una causa comune di questo problema è quando si invia una LAN o altra connessione di rete relativamente veloce e un computer è significativamente più veloce dell'altro computer. Come esempio estremo, diciamo che hai un computer 3Ghz che invia il più velocemente possibile su un Gigabit Ethernet a un altro computer che esegue una CPU da 1 Ghz. Poiché il mittente può inviare molto più velocemente di quanto il ricevitore sia in grado di leggere, il buffer del ricevitore si riempirà facendo in modo che lo stack TCP pubblicizzi una finestra Zero sul mittente.
Ora questo può causare problemi sia sul lato di invio che su quello di ricezione se non sono entrambi pronti ad affrontare questo problema. Sul lato dell'invio, ciò può causare il riempimento del buffer di invio e le chiamate da inviare a bloccare o fallire se si utilizza I/O non bloccante. Dal lato ricevente si potrebbe passare così tanto tempo sull'I/O che l'applicazione non ha la possibilità di elaborare alcuno dei suoi dati e dando l'impressione di essere rinchiuso.
Modifica
Da alcune delle sue risposte e il codice che suona come la vostra applicazione è a thread singolo e si sta cercando di fare non-blocking manda per qualche ragione. Presumo che tu stia impostando il socket su non-Blocking in qualche altra parte del codice.
In generale, direi che questa non è una buona idea. Idealmente, se siete preoccupati per la vostra applicazione appesa a un send(2)
si dovrebbe impostare un lungo timeout sul socket utilizzando setsockopt
e usare un thread separato per l'invio vero e proprio.
Vedi socket(7):
SO_RCVTIMEO e SO_SNDTIMEO Specificare la ricezione o l'invio di timeout fino segnalato un errore. Il parametro è una struct timeval. Se un input o output blocchi funzionali per questo periodo di tempo, ei dati sono stati inviati o ricevuti, il valore restituito di che funzione sarà la quantità di dati trasferiti ; se nessun dato è stato trasferito e il timeout è stato raggiunto allora -1 viene restituito con errno impostato su EAGAIN o EWOULDBLOCK come se il socket è stato specificato come non bloccante. Se il timeout è impostato su zero (il default) allora l'operazione non sarà mai timeout.
tuo thread principale può spingere ogni descrittore di file in un queue
utilizzando dire un mutex spinta per l'accesso di coda, quindi avviare 1 - N thread per fare l'invio effettivo utilizzando il blocco di I/O con mando timeout.
La funzione di invio dovrebbe essere simile a questa (supponendo che si sta impostando un timeout):
// blocking send, timeout is handled by caller reading errno on short send
int doSend(int s, const void *buf, size_t dataLen) {
int totalSent=0;
while(totalSent != dataLen)
{
int bytesSent
= send(s,((char *)data)+totalSent, dataLen-totalSent, MSG_NOSIGNAL);
if(bytesSent < 0 && errno != EINTR)
break;
totalSent += bytesSent;
}
return totalSent;
}
La bandiera MSG_NOSIGNAL
assicura che l'applicazione non viene ucciso scrivendo ad una presa che è stato chiuso o resettato dal pari. A volte le operazioni di I/O vengono interrotte dai segnali e il controllo di EINTR
consente di riavviare lo send
.
In generale, si dovrebbe chiamare doSend
in un ciclo con blocchi di dati che sono di TCP_MAXSEG
dimensioni.
Sul lato ricezione è possibile scrivere una analoga funzione di blocco recv utilizzando un timeout in un thread separato.
Maggiori dettagli? Il file viene trasferito correttamente, solo a una velocità inferiore o il trasferimento non riesce? Se sta fallendo, dove sta fallendo? Qualcosa sta attraversando o sta fallendo a metà? –
@Robert, grazie. Il trasferimento fallisce. Se trasferisco una cartella contiene, ad esempio, 2 GB di 3 KB - 50 KB di file, trasferisce a volte ~ 0,5 GB, a volte ~ 1,3 GB di dati e quindi non riesce. – rkellerm
Che messaggi di errore si stanno ottenendo e da che parte si sta spegnendo la connessione? Stai usando I/O bloccanti o non bloccanti. Hai un thread dedicato facendo I/O? Più dettagli ci sono, meglio è, e se potessi pubblicare frammenti di codice sarebbe il migliore. –