it-swarm.com.de

104, Socket-Fehler 'Verbindung durch Peer zurückgesetzt' oder Wann führt das Schließen eines Sockets zu einem RST und nicht zu einem FIN?

Wir entwickeln parallel einen Python Web-Service und eine Client-Website. Wenn wir eine HTTP-Anfrage vom Client an den Service senden, löst ein Aufruf konsistent einen socket.error in socket.py aus , in gelesen:

(104, 'Verbindung von Peer zurückgesetzt')

Wenn ich mit wireshark zuhöre, sehen die "guten" und "schlechten" Antworten sehr ähnlich aus:

  • Aufgrund der Größe des OAuth - Headers wird die Anforderung in zwei Pakete aufgeteilt. Der Dienst antwortet auf beide mit ACK
  • Der Dienst sendet die Antwort, ein Paket pro Header (HTTP/1.0 200 OK, dann der Date-Header usw.). Der Kunde antwortet jeweils mit ACK.
  • (Gute Anfrage) Der Server sendet eine FIN, ACK. Der Kunde antwortet mit einem FIN, ACK. Der Server antwortet mit ACK.
  • (Falsche Anfrage) Der Server sendet eine RST, ACK, der Client sendet keine TCP Antwort, der socket.error wird auf der Client-Seite ausgelöst.

Sowohl der Webdienst als auch der Client laufen auf einer Gentoo Linux x86-64-Box mit glibc-2.6.1. Wir verwenden Python 2.5.2 in derselben virtual_env.

Der Client ist eine Django 1.0.2 App, die httplib2 0.4.0 aufruft, um Anfragen zu stellen. Wir signieren Anfragen mit dem OAuth= Signaturalgorithmus, mit Das OAuth Token wird immer auf eine leere Zeichenfolge gesetzt.

Auf dem Dienst wird Werkzeug 0.3.1 ausgeführt, das Pythons wsgiref.simple_server verwendet. Ich habe die WSGI-App ohne Probleme über wsgiref.validator ausgeführt.

Es scheint, dass dies leicht zu debuggen sein sollte, aber wenn ich eine gute Anfrage auf der Serviceseite nachverfolge, sieht es genauso aus wie die schlechte Anfrage in der Funktion socket._socketobject.close (), die Delegate-Methoden in Dummy-Methoden verwandelt. Wenn die Methode send oder sendto (kann sich nicht erinnern, welche) ausgeschaltet ist, wird FIN oder RST gesendet und der Client beginnt mit der Verarbeitung.

"Connection reset by peer" scheint dem Dienst die Schuld zu geben, aber ich vertraue auch httplib2 nicht. Kann der Kunde Schuld haben?

** Weiteres Debuggen - Sieht aus wie ein Server unter Linux **

Ich besitze ein MacBook und habe versucht, den Dienst auf der einen und die Client-Website auf der anderen Seite auszuführen. Der Linux-Client ruft den OS X-Server fehlerfrei auf (FIN ACK). Der OS X-Client ruft den Linux-Dienst mit dem Fehler (RST ACK und a (54, 'Connection reset by peer')) auf. Es sieht also so aus, als ob es sich um den Dienst handelt, der unter Linux ausgeführt wird. Ist es x86_64? Eine schlechte Sache? wsgiref? Immer noch suchend...

** Weitere Tests - wsgiref sieht schuppig aus **

Wir sind mit Apache und mod_wsgi in die Produktion gegangen, und die Verbindungszurücksetzungen sind verschwunden. Siehe meine Antwort unten, aber mein Rat ist, das Zurücksetzen der Verbindung zu protokollieren und es erneut zu versuchen. Auf diese Weise läuft Ihr Server im Entwicklungsmodus einwandfrei und in der Produktion einwandfrei.

30
jwhitlock

Ich habe dieses Problem gehabt. Siehe Das Python "Connection Reset By Peer" -Problem .

Sie haben (höchstwahrscheinlich) mit kleinen Timing-Problemen zu kämpfen, die auf der Python Global Interpreter Lock) basieren.

Sie können dies (manchmal) mit einer strategisch platzierten time.sleep(0.01) korrigieren.

"Wo?" du fragst. Schlägt mich. Die Idee ist, eine bessere Thread-Parallelität in und um die Client-Anforderungen bereitzustellen. Versuchen Sie es einfach , bevor Sie die Anfrage stellen, damit die GIL zurückgesetzt wird und der Python Interpreter alle löschen kann ausstehende Threads.

21
S.Lott

Verwenden Sie wsgiref nicht für die Produktion. Verwenden Sie Apache und mod_wsgi oder etwas anderes.

Wir sehen weiterhin, dass diese Verbindungen manchmal häufig mit wsgiref zurückgesetzt werden (das vom werkzeug-Testserver verwendete Backend und möglicherweise auch andere wie der Django Testserver). Unsere Lösung bestand darin, den Fehler zu protokollieren. Wiederholen Sie den Aufruf in einer Schleife und geben Sie nach zehn Fehlern auf. httplib2 versucht es zweimal, aber wir brauchten noch ein paar weitere. Sie scheinen auch in Bündeln zu kommen - durch Hinzufügen eines 1-Sekunden-Ruhezustands wird das Problem möglicherweise behoben.

Beim Ausführen von Apache und mod_wsgi wurde die Verbindung noch nie zurückgesetzt. Ich weiß nicht, was sie anders machen (vielleicht maskieren sie sie nur), aber sie erscheinen nicht.

Als wir die lokale Entwickler-Community um Hilfe fragten, bestätigte jemand, dass viele Verbindungszurücksetzungen mit wsgiref auf dem Produktionsserver nicht mehr möglich sind. Es gibt dort einen Fehler, aber es wird schwierig sein, ihn zu finden.

11
jwhitlock

Mir ist klar, dass Sie Python verwenden, aber ich fand diesen Java Artikel nützlich.

http://Java.Sun.com/javase/6/docs/technotes/guides/net/articles/connection_release.html

5
Sean McCauliff

Normalerweise erhalten Sie eine RST, wenn Sie einen Abschluss durchführen, der nicht verweilt (dh, in dem Daten vom Stapel verworfen werden können, wenn sie nicht gesendet und mit ACK bestätigt wurden), und eine normale FIN, wenn Sie den Abschluss zulassen zum Verweilen (dh das Schließen wartet darauf, dass die Daten während der Übertragung bestätigt werden).

Vielleicht müssen Sie Ihren Socket nur so einstellen, dass er verweilt, damit Sie die Wettlaufsituation zwischen einem nicht verweilenden Schließen des Sockets und dem Eintreffen der ACKs aufheben können?

2
Len Holgate

Ich hatte jedoch das gleiche Problem beim Hochladen einer sehr großen Datei mit einem Python-Requests-Client, der in einem nginx + uwsgi-Backend postet.

Was letztendlich die Ursache war, war, dass das Backend die maximale Dateigröße für Uploads begrenzt hatte, die niedriger war als die, die der Client zu senden versuchte.

Der Fehler wurde in unseren uwsgi-Protokollen nie angezeigt, da dieses Limit tatsächlich von nginx festgelegt wurde.

Das Erhöhen des Limits in Nginx behebt den Fehler.

1
David Simic