Was kann ich tun, um zu vermeiden, TCP Zero Window - / TCP-Fenster-Voll auf der Empfänger Seite?
Ich habe eine kleine Anwendung, die sendet Dateien über das Netzwerk an einen agent, der auf Windows OS.
Wenn diese Anwendung läuft auf Windows funktioniert alles einwandfrei, die Kommunikation ist OK und die Dateien sind alle erfolgreich kopiert.
Aber, wenn diese Anwendung läuft auf Linux (RedHat 5.3, der Empfänger ist immer noch Windows), sehe ich in Wireshark Netzwerk-trace-messages von TCP Zero Window und TCP Window Full erscheint auf jeweils 1-2 Sekunden. Der agent schließt dann die Verbindung nach ein paar Minuten.
Den Windows - Linux-code ist fast das gleiche und ziemlich einfach. Die einzige nicht-triviale operation ist setsockopt mit SO_SNDBUF und mit dem Wert 0xFFFF. Das entfernen dieser code hat nicht geholfen.
Kann mir bitte jemand helfen mit diesem Problem?
EDIT: hinzufügen das senden von code - es sieht aus, dass es behandelt teilweise richtig schreibt:
int totalSent=0;
while(totalSent != dataLen)
{
int bytesSent
= ::send(_socket,(char *)(data+totalSent), dataLen-totalSent, 0);
if (bytesSent ==0) {
return totalSent;
}
else if(bytesSent == SOCKET_ERROR){
#ifdef __WIN32
int errcode = WSAGetLastError();
if( errcode==WSAEWOULDBLOCK ){
#else
if ((errno == EWOULDBLOCK) || (errno == EAGAIN)) {
#endif
}
else{
if( !totalSent ) {
totalSent = SOCKET_ERROR;
}
break;
}
}
else{
totalSent+=bytesSent;
}
}
}
Vielen Dank im Voraus.
- Mehr details? Ist die Datei erfolgreich übertragen, nur in einem langsameren Tempo oder die übertragung fehlschlägt? Wenn es fehlschlägt, ist, wo ist er aufgetreten? Ist alles immer über oder wird es scheitern auf halbem Weg durch?
- danke. Die übertragung schlägt fehl. Wenn ich ein Ordner enthält, zum Beispiel, 2 GB 3 KB - 50 KB Dateien, überträgt es manchmal ~0,5 GB, manchmal ~1,3 GB Daten und dann scheitert.
- Welche Fehlermeldungen Sie erhalten und welche Seite ist das Herunterfahren der Verbindung? Sind Sie auf der Verwendung von blockierenden oder nicht-blockierenden I/O. Sie haben einen dedizierten thread zu tun I/O? Je mehr details, desto besser, und wenn Sie könnten post-code-Fragmente, die wäre die beste.
- Was ist
::send(...)
? Ist dieser ein Mitglied der Klasse die wraps die standard -send(...)
Funktion? - Können Sie nach dem Empfang der code auch? Es klingt wie Daten möglicherweise nicht immer abgerissen werden, auf der Empfängerseite.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Sehen nicht deinen code, ich werde zu erraten.
Der Grund, warum Sie eine Null-Fenster in TCP ist, weil es keine Zimmer in den receiver-recv-Puffer.
Gibt es eine Reihe von Möglichkeiten, das kann vorkommen. Eine häufige Ursache dieses Problems ist, wenn Sie das senden über ein LAN oder andere relativ schnelle Netzwerk-Verbindung und einem computer ist deutlich schneller als die anderen computer. Als ein extremes Beispiel, sagen, Sie habe einen 3Ghz Rechner das senden so schnell wie möglich über ein Gigabit-Ethernet auf einen anderen Rechner mit einer 1 GHz cpu. Da der sender senden kann, viel schneller als der Empfänger in der Lage zu Lesen, dann den Empfänger recv buffer füllt, wodurch die TCP-stack, um Werbung für ein Zero window an den sender.
Nun dies kann Probleme verursachen, sowohl das senden und empfangen von Seiten, wenn Sie nicht beide bereit sind, um damit umzugehen. Auf der sendenden Seite kann dadurch den sende-Puffer zu füllen und Anrufe zu senden, entweder um zu blockieren oder zu scheitern, wenn Sie mit non-blocking I/O. Auf der empfangenden Seite könnten Sie verbringen so viel Zeit auf I/O, dass der Antrag keine chance hat, Bearbeiten Sie die Daten und geben das Aussehen des seins eingesperrt.
Bearbeiten
Von einigen Ihrer Antworten und Codes, es klingt wie Ihre app ist single-threaded und man versucht, etwas zu tun, non-Blocking sendet aus irgendeinem Grund. Ich nehme an, Sie sind die Einstellung der socket auf non-Blocking in einen anderen Teil des Codes.
Generell würde ich sagen, dass dies nicht eine gute Idee. Ideal, wenn Sie sind besorgt über Ihre app hängen an einem
send(2)
sollten Sie eine lange timeout auf den socket mitsetsockopt
und verwenden Sie einen separaten thread für das eigentliche versenden.Sehen socket(7):
Ihre Haupt-thread schieben können jede Datei-Deskriptor in einem
queue
mit sagen einen Schub mutex für die queue zugreifen, dann start-1 - N threads für die eigentliche Versendung mit blocking I/O mit sende-timeouts.Ihre send-Funktion sollte in etwa so Aussehen ( angenommen, Sie sind eine timeout-Einstellung ):
Den
MSG_NOSIGNAL
fahne sorgt dafür, dass Ihre Anwendung nicht getötet werden durch das schreiben in einen socket, der geschlossen worden ist oder reset by peer. Manchmal I/O-Operationen werden unterbrochen durch Signale, die PrüfungEINTR
können Sie starten Sie densend
.In der Regel, sollten Sie rufen
doSend
in einer Schleife mit Stücken von Daten, die vonTCP_MAXSEG
Größe.Auf der Seite erhalten, können Sie schreiben, eine ähnliche Blockierung "recv" - Vorgang-Funktion mit einem timeout in einem separaten thread.
MSG_NOSIGNAL
wobei ich denke, dass mein problem auf einer meiner Anwendungen.Ein häufiger Fehler bei der Entwicklung von mit TCP-sockets über falsche Annahme über read()/write() Verhalten.
Beim ausführen einer lese/schreib-operation müssen Sie den Rückgabewert überprüfen, können Sie nicht Lesen/schreiben der angeforderten bytes, benötigen Sie in der Regel eine Schleife zu verfolgen und sicherzustellen, dass die gesamten Daten übertragen wurde.
Das wahrscheinlichste problem ist, dass Sie einen Fehler in Ihrem code, wo Sie nicht behandeln, teilweise Lesen oder teilweise richtig schreibt. TCP zwischen Linux und Windows bekannt ist.
Habe ich versucht zu deaktivieren Nagle-Algorithmus (mit TCP_NODELAY), und irgendwie half es.
Übertragungsrate ist viel höher, TCP-Fenster nicht voll ist oder zurückgesetzt wird.
Das merkwürdige ist, dass wenn ich chaged die Größe der Fenster hat es leider keine Auswirkung.
Danke.