Warum sendet DefaultHttpClient Daten über einen halbgeschlossenen Socket?

9

Ich verwende DefaultHttpClient mit einem ThreadSafeClientConnManager auf Android (2.3.x), um HTTP-Anfragen an einen my REST-Server (eingebetteter Jetty) zu senden.

Nach ca. 200 Sekunden Leerlaufzeit schließt der Server die TCP-Verbindung mit einem [FIN]. Der Android-Client antwortet mit einem [ACK]. Dies sollte und lässt den Socket in einem halbgeschlossenen Zustand (der Server hört zwar noch zu, kann aber keine Daten senden).

Ich würde erwarten, dass, wenn der Client versucht, diese Verbindung erneut zu verwenden (via HttpClient.execute ), DefaultHttpClient den halbgeschlossenen Zustand erkennt, den Socket auf der Client-Seite schließt (also sendet [FIN / ACK] um das Schließen zu beenden) und eine neue Verbindung für die Anfrage öffnen. Aber da ist der Haken.

Stattdessen sendet es die neue HTTP-Anforderung über den halbgeschlossenen Socket. Erst nach dem Senden wird der halbgeschlossene Zustand erkannt und der Socket auf der Client-Seite geschlossen (mit [FIN] an den Server gesendet). Natürlich kann der Server nicht auf die Anfrage antworten (er hatte bereits seine [FIN] gesendet), daher denkt der Client, dass die Anfrage fehlgeschlagen ist und wiederholt automatisch über einen neuen Socket / Verbindung.

Das Endergebnis ist, dass der Server zwei Kopien der Anfrage sieht und verarbeitet.

Irgendwelche Ideen, wie Sie das beheben können? (Mein Server tut das Richtige mit der zweiten Kopie, aber ich bin verärgert, dass die Payload zweimal übertragen wird.)

Sollte DefaultHttpClient nicht feststellen, dass der Socket beim ersten Versuch, das neue HTTP-Paket zu schreiben, geschlossen wurde, diesen Socket sofort schließen und einen neuen starten? Ich bin verblüfft darüber, wie eine neue HTTP-Anfrage auf einem Socket gesendet wird, Minuten nachdem der Server ein [FIN] gesendet hat.

    
David B. 27.06.2012, 04:17
quelle

1 Antwort

5

Dies ist eine allgemeine Einschränkung der blockierenden E / A in Java. Es gibt einfach keine Möglichkeit, herauszufinden, ob der andere Endpunkt eine Verbindung geschlossen hat oder nicht, als wenn versucht wird, aus dem Socket zu lesen. Apache HttpClient arbeitet dieses Problem um, indem er die so alte Verbindungsprüfung anwendet, die im Wesentlichen eine sehr kurze Leseoperation ist. Die Überprüfung kann und wird jedoch oft deaktiviert. In der Tat ist es oft ratsam, es aufgrund der zusätzlichen Latenz, die der Check einführt, zu deaktivieren. Ich habe keine Ahnung, wie genau die Version von HttpClient, die mit Android ausgeliefert wird, sich in dieser Hinsicht verhält, aber Sie könnten versuchen, die Überprüfung explizit zu aktivieren, indem Sie einen geeigneten Konfigurationsparameter verwenden.

Eine bessere Lösung für dieses Problem besteht möglicherweise darin, Verbindungen aus dem Verbindungspool zu entfernen, die nach einer bestimmten Inaktivitätszeit über einen bestimmten Zeitraum (z. B. 150 Sekunden) inaktiv waren.

Ссылка

    
oleg 28.06.2012, 14:03
quelle