Pourquoi DefaultHttpClient envoie-t-il des données via un socket semi-fermé?

J’utilise DefaultHttpClient avec un ThreadSafeClientConnManager sur Android (2.3.x) pour envoyer des demandes HTTP à un serveur REST (ma Jetty intégrée).

Après environ 200 secondes d’inactivité, le serveur ferme la connexion TCP avec un [FIN]. Le client Android répond avec un [ACK]. Cela devrait laisser le socket dans un état semi-fermé (le serveur écoute toujours, mais ne peut pas envoyer de données).

Je m’attendrais à ce que lorsque le client essaie à nouveau d’utiliser cette connexion (via HttpClient.execute ), DefaultHttpClient détecte l’état semi-fermé, ferme le socket côté client (envoyant ainsi [FIN / ACK] pour finaliser la fermeture) et ouvrez une nouvelle connexion pour la demande. Mais voilà le hic.

Au lieu de cela, il envoie la nouvelle requête HTTP sur le socket à moitié fermé. Après envoi, l’état semi-fermé est détecté et le socket est fermé côté client (avec [FIN] envoyé au serveur). Bien sûr, le serveur ne peut pas répondre à la demande (il a déjà envoyé son [FIN]), donc le client pense que la demande a échoué et relance automatiquement via une nouvelle connexion / socket.

Le résultat final est que le serveur voit et traite deux copies de la demande.

Des idées pour résoudre le problème? (Mon serveur fait le bon choix avec la deuxième copie, mais je suis fâché que la charge utile soit transmise deux fois.)

DefaultHttpClient ne devrait-il pas détecter que le socket a été fermé lors de la première tentative d’écriture du nouveau paquet HTTP, fermer immédiatement ce socket et en démarrer un nouveau? Je suis perplexe quant à la manière dont une nouvelle requête HTTP est envoyée sur un socket quelques minutes après que le serveur a envoyé un [FIN].

Il s’agit d’une limitation générale des E / S de blocage en Java. Il n’y a tout simplement aucun moyen de savoir si le point d’extrémité opposé a fermé la connexion autrement qu’en essayant de lire à partir du socket. Apache HttpClient résout ce problème en utilisant la vérification de connexion obsolète, qui est essentiellement une opération de lecture très brève. Cependant, le contrôle peut et est souvent désactivé. En fait, il est souvent conseillé de le désactiver en raison du temps de latence supplémentaire introduit par le contrôle. Je ne sais pas du tout à quel point la version de HttpClient fournie avec Android se comporte à cet égard, mais vous pouvez essayer explicitement d’activer le contrôle en utilisant un paramètre de configuration approprié.

Une meilleure solution à ce problème pourrait être d’exclure des connexions du pool de connexions inactives au cours d’une période donnée (par exemple 150 secondes) après une période d’inactivité.

http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmm.html#d5e652