network-programming - example - httpurlconnection java
Implementacion HttpURLConnection (6)
He leído que HttpURLConnection admite conexiones persistentes, de modo que una conexión se puede reutilizar para múltiples solicitudes. Lo intenté y la única forma de enviar un segundo POST fue llamando a openConnection por segunda vez. De lo contrario, obtuve una IllegalStateException ("Ya estoy conectado"); Utilicé lo siguiente:
try{
URL url = new URL("http://someconection.com");
}
catch(Exception e){}
HttpURLConnection con = (HttpURLConnection) url.openConnection();
//set output, input etc
//send POST
//Receive response
//Read whole response
//close input stream
con.disconnect();//have also tested commenting this out
con = (HttpURLConnection) url.openConnection();
//Send new POST
La segunda solicitud se envía a través de la misma conexión TCP (verificada con wireshark) pero no puedo entender por qué (aunque esto es lo que quiero) ya que he llamado desconectar. Verifiqué el código fuente de HttpURLConnection y la implementación mantiene una memoria caché de conexiones a los mismos destinos. Mi problema es que no puedo ver cómo se vuelve a colocar la conexión en el caché después de haber enviado la primera solicitud. La desconexión cierra la conexión y, sin la desconexión, aún no puedo ver cómo se vuelve a colocar la conexión en el caché. Vi que la memoria caché tiene un método de ejecución para pasar por todas las conexiones inactivas (no estoy seguro de cómo se llama), pero no puedo encontrar cómo se vuelve a colocar la conexión en la memoria caché. El único lugar en el que parece ocurrir es en el método terminado de httpClient, pero no se llama para un POST con una respuesta. ¿Puede alguien ayudarme con esto?
EDITAR Mi interés es cuál es el manejo adecuado de un objeto HttpUrlConnection para la reutilización de la conexión tcp. En caso de que el flujo de entrada / salida se cierre seguido de url.openConnection (); ¿Cada vez para enviar la nueva solicitud (evitando desconectar ())? En caso afirmativo, no puedo ver cómo se reutiliza la conexión cuando llamo a url.openConnection () por segunda vez, ya que la conexión se eliminó de la caché para la primera solicitud y no puedo encontrar cómo se devuelve. ¿Es posible que la conexión no se devuelva a la memoria caché de keepalive (error?), Pero el sistema operativo no ha liberado todavía la conexión tcp y en la nueva conexión, el sistema operativo devuelve la conexión almacenada (aún no liberada) o algo similar? EDIT2 El único relacionado que encontré fue de JDK_KeepAlive
... cuando la aplicación llama a close () en el InputStream devuelto por URLConnection.getInputStream (), el controlador de protocolo HTTP del JDK intentará limpiar la conexión y, si tiene éxito, coloque la conexión en un caché de conexión para que la reutilicen futuras solicitudes HTTP. .
Pero no estoy seguro de qué manejador es este. sun.net.www.protocol.http.Handler no hace ningún almacenamiento en caché como lo vi ¡Gracias!
¿Cómo se "fuerza el uso de HTTP1.0" utilizando la conexión HttpUrl de JDK?
De acuerdo con la sección JDK_KeepAlive soporte para conexiones HTTP1.1 se puede activar o desactivar mediante la propiedad de Java http.keepAlive
(el valor predeterminado es verdadero). Además, la propiedad java http.maxConnections
indica el número máximo de conexiones (concurrentes) por destino que se mantendrán activas en un momento dado.
Por lo tanto, un "uso forzoso de HTTP1.0" se podría aplicar a toda la aplicación de una vez estableciendo la propiedad java http.keepAlive
en falso.
En caso de que el flujo de entrada / salida se cierre seguido de url.openConnection (); ¿Cada vez para enviar la nueva solicitud (evitando desconectar ())?
Sí.
En caso afirmativo, no puedo ver cómo se reutiliza la conexión cuando llamo a url.openConnection () por segunda vez, ya que la conexión se eliminó de la caché para la primera solicitud y no puedo encontrar cómo se devuelve.
HttpURLConnection
el HttpURLConnection
con el Socket
subyacente y su conexión TCP subyacente. No son lo mismo. Las instancias de HttpURLConnection
son GC''d, el Socket
subyacente se agrupa, a menos que llame a disconnect().
Abandonar secuencias causará conexiones TCP inactivas. La secuencia de respuesta debe leerse completamente. Otra cosa que pasé por alto inicialmente y que he visto pasada por alto en la mayoría de las respuestas sobre este tema es olvidarme de tratar con la secuencia de errores en caso de excepciones. El código similar a este corrigió una de mis aplicaciones que no liberaba los recursos correctamente:
HttpURLConnection connection = (HttpURLConnection)new URL(uri).openConnection();
InputStream stream = null;
BufferedReader reader = null;
try {
stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream, Charset.forName("UTF-8")));
// do work on part of the input stream
} catch (IOException e) {
// read the error stream
InputStream es = connection.getErrorStream();
if (es != null) {
BufferedReader esReader = null;
esReader = new BufferedReader(new InputStreamReader(es, Charset.forName("UTF-8")));
while (esReader.ready() && esReader.readLine() != null) {
}
if (esReader != null)
esReader.close();
}
// do something with the IOException
} finally {
// finish reading the input stream if it was not read completely in the try block, then close
if (reader != null) {
while (reader.readLine() != null) {
}
reader.close();
}
// Not sure if this is necessary, closing the buffered reader may close the input stream?
if (stream != null) {
stream.close();
}
// disconnect
if (connection != null) {
connection.disconnect();
}
}
El lector con buffer no es estrictamente necesario, lo elegí porque mi caso de uso requería leer una línea a la vez.
Consulte también: http://docs.oracle.com/javase/1.5.0/docs/guide/net/http-keepalive.html
Descubrí que la conexión se almacena en caché cuando se cierra InputStream. Una vez que se ha cerrado el inputStream, la conexión subyacente se almacena en búfer. Sin embargo, el objeto HttpURLConnection no se puede utilizar para otras solicitudes, ya que el objeto se considera todavía "conectado", es decir, su booleano conectado se establece en verdadero y no se borra una vez que la conexión se vuelve a colocar en el búfer. Por lo tanto, cada vez que se instale una nueva HttpUrlConnection para una nueva POST, la conexión TCP subyacente se reutilizará, si no se ha agotado el tiempo de espera. Así que la respuesta de EJP fue la descripción correcta. ¿Puede ser el comportamiento que vi (la reutilización de la conexión TCP) a pesar de haber llamado explícitamente a disconnect () se debió al almacenamiento en caché realizado por el sistema operativo? No lo sé. Espero que alguien que sabe pueda explicar. Gracias.
Desde el javadoc para HttpURLConnection (mi énfasis):
Cada instancia de HttpURLConnection se usa para realizar una sola solicitud, pero la conexión de red subyacente al servidor HTTP puede ser compartida de manera transparente por otras instancias. La llamada a los métodos close () en InputStream o OutputStream de un HttpURLConnection después de una solicitud puede liberar recursos de red asociados con esta instancia, pero no tiene efecto en ninguna conexión persistente compartida. Llamar al método disconnect () puede cerrar el socket subyacente si una conexión persistente está inactiva en ese momento.
Hmmh Puede que me falte algo aquí (ya que esta es una pregunta antigua), pero que yo sepa, hay dos formas bien conocidas de forzar el cierre de la conexión TCP subyacente:
- Forzar el uso de HTTP 1.0 (1.1 introdujo conexiones persistentes) - esto como lo indica la línea de solicitud http
- Enviar ''Conexión'' encabezado con el valor ''cerrar''; Esto forzará el cierre también.