Wenn Sie Ihren Code nicht sehen, muss ich raten.
Der Grund, warum Sie ein Zero-Fenster in TCP erhalten, liegt darin, dass im Recv-Puffer des Empfängers kein Platz ist.
Es gibt eine Reihe von Möglichkeiten, wie dies auftreten kann. Eine häufige Ursache für dieses Problem ist, wenn Sie über ein LAN oder eine andere relativ schnelle Netzwerkverbindung senden und ein Computer wesentlich schneller ist als der andere Computer. Als ein extremes Beispiel, sagen Sie, dass Sie einen 3Ghz-Computer haben, der so schnell wie möglich über ein Gigabit-Ethernet zu einem anderen Computer sendet, der eine 1-GHz-CPU betreibt. Da der Sender viel schneller senden kann, als der Empfänger lesen kann, füllt sich der recv-Puffer des Empfängers, was bewirkt, dass der TCP-Stapel dem Absender ein Zero-Fenster ankündigt.
Nun kann dies Probleme sowohl auf der Sende- als auch auf der Empfangsseite verursachen, wenn sie nicht beide bereit sind, damit umzugehen. Auf der sendenden Seite kann dies dazu führen, dass der Sendepuffer voll wird, und Aufrufe, um entweder zu blockieren oder fehlzuschlagen, wenn Sie nicht blockierende E/A verwenden. Auf der Empfängerseite könnten Sie so viel Zeit mit I/O verbringen, dass die Anwendung keine Möglichkeit hat, irgendwelche ihrer Daten zu verarbeiten und den Anschein zu erwecken, eingesperrt zu sein.
bearbeiten
Von einigen Ihrer Antworten und Code klingt es wie Ihre Anwendung Gewinde Single ist und Sie versuchen, nicht-Blocking aus irgendeinem Grund sendet zu tun. Ich nehme an, dass Sie den Socket in einem anderen Teil des Codes auf Nicht-Blockieren setzen.
Generell würde ich sagen, dass dies keine gute Idee ist. Wenn Sie befürchten, dass Ihre App auf send(2)
hängt, sollten Sie idealerweise eine lange Zeitüberschreitung für den Socket unter Verwendung von setsockopt
festlegen und einen separaten Thread für das eigentliche Senden verwenden.
Siehe socket(7):
SO_RCVTIMEO und SO_SNDTIMEO die Empfangs Geben oder das Versenden von Timeouts, bis ein Fehler meldet. Der Parameter ist ein Strukturzeitval. Wenn eine Eingangs- oder Ausgangsfunktion für diese Zeitspanne sperrt und Daten gesendet oder empfangen wurden, wird der Rückgabewert diese Funktion die Menge der übertragenen Daten sein; Wenn keine Daten übertragen wurden und das Zeitlimit erreicht wurde, wird -1 zurückgegeben, wobei errno auf EAGAIN oder EWOULDBLOCK gesetzt ist, genauso wie , wenn der Socket als nicht blockierend festgelegt wurde. Wenn das Zeitlimit auf Null (Standardeinstellung) gesetzt ist, wird die Operation niemals ablaufen.
Ihr Hauptthread kann jede Dateideskriptor in ein queue
drücken, um einen Schub für Mutex Warteschlange Zugriff mit sagen, beginnt dann 1 - N Threads die tatsächlichen zu tun Senden I unter Verwendung von blockierenden/O mit Timeouts senden.
Ihre Sendefunktion sollte wie folgt aussehen (vorausgesetzt, Sie ein Timeout sind Einstellung):
// 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;
}
Die MSG_NOSIGNAL
Flagge stellt sicher, dass Ihre Anwendung nicht durch das Schreiben an eine Steckdose getötet wird, der geschlossen worden ist oder zurückgesetzt durch den Peer. Manchmal werden E/A-Vorgänge durch Signale unterbrochen, und die Überprüfung auf EINTR
ermöglicht es Ihnen, die send
neu zu starten.
Im Allgemeinen sollten Sie doSend
in einer Schleife mit Datenbrocken der TCP_MAXSEG
Größe aufrufen.
Auf der Empfangsseite können Sie eine ähnliche blockierende recv-Funktion schreiben, die ein Timeout in einem separaten Thread verwendet.
Weitere Details? Wird die Datei erfolgreich übertragen, nur mit einer langsameren Geschwindigkeit oder schlägt die Übertragung fehl? Wenn es scheitert, wo versagt es? Passiert etwas oder fällt es auf halbem Wege aus? –
@Robert, danke. Die Übertragung schlägt fehl. Wenn ich einen Ordner mit zB 2 GB 3 KB - 50 KB Dateien übertrage, überträgt er manchmal ~ 0,5 GB, manchmal ~ 1,3 GB Daten und schlägt dann fehl. – rkellerm
Welche Fehlermeldungen erhalten Sie und welche Seite beendet die Verbindung? Verwenden Sie blockierende oder nicht blockierende E/A. Haben Sie einen dedizierten Thread, der I/O erledigt? Je mehr Details, desto besser, und wenn Sie Code-Fragmente buchen könnten, wäre das am besten. –