implementazione HttpURLConnection
-
27-09-2019 - |
Domanda
Ho letto che HttpURLConnection supporta connessioni persistenti, in modo che una connessione può essere riutilizzato per richieste multiple. L'ho provato e l'unico modo per inviare un secondo POST era chiamando OpenConnection per la seconda volta. In caso contrario, ho ottenuto un IllegalStateException ( "Già collegata"); Ho usato il seguente:
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 seconda richiesta è inviare sulla stessa connessione TCP (verificato con wireshark), ma non riesco a capire il motivo per cui (anche se questo è quello che voglio) dato che ho chiamato disconnessione. Ho controllato il codice sorgente per il HttpURLConnection e l'implementazione non mantenere una cache keepalive di connessioni per le stesse destinazioni. Il mio problema è che non riesco a vedere come la connessione viene rimesso nella cache dopo che ho inviare la prima richiesta. La disconnessione chiude la connessione e senza la disconnessione, ancora non riesco a vedere come la connessione viene rimesso nella cache. Ho visto che la cache ha un metodo run di passare attraverso più di tutte le connessioni inattive (non sono sicuro di come viene chiamato), ma non riesco a trovare il modo la connessione viene rimesso nella cache. L'unico posto che sembra accadere è nel metodo finita di HttpClient ma questo non è richiesto un POST con una risposta. Chiunque può aiutare me su questo?
Modifica Il mio interesse è, qual è la corretta manipolazione di un oggetto HttpURLConnection per il riutilizzo connessione TCP. flusso di ingresso / uscita dovrebbero essere chiusi seguito da un url.openConnection (); ogni tempo per inviare la nuova richiesta (evitando di disconnessione ())? Se sì, non riesco a vedere come la connessione viene riutilizzata quando chiamo url.openConnection () per la seconda volta, dal momento che il collegamento è stato rimosso dalla cache per la prima richiesta e non riesce a trovare come si è restituito di nuovo. E 'possibile che la connessione non è restituito di nuovo alla cache keepalive (bug?), Ma il sistema operativo non ha ancora rilasciato la connessione TCP e sulla nuova connessione, il sistema operativo restituisce la connessione tamponata (non ancora rilasciato) o qualcosa di simile? EDIT2 L'scoperto che solo legati era da JDK_KeepAlive
... quando l'applicazione chiama close () sul InputStream restituito da URLConnection.getInputStream (), la gestore di protocollo HTTP del JDK proverà per ripulire la connessione e, se successo, mettere il collegamento in un cache di connessione per il riutilizzo per il futuro le richieste HTTP.
Ma io non sono sicuro di quale gestore è questo. sun.net.www.protocol.http.Handler non fa alcun caching come ho visto Grazie!
Soluzione
flusso di input / output deve essere chiusa seguito da un url.openConnection (); ogni volta per inviare la nuova richiesta (Evitando di disconnessione ())?
Sì.
Se sì, non riesco a vedere come la connessione viene riutilizzato quando chiamo url.openConnection () per la seconda il tempo, dal momento che la connessione è stata rimosso dalla cache per la prima richiesta e non può trovare come è indietro restituito.
Si confondono la HttpURLConnection
con la Socket
sottostante e la sua sottostante connessione TCP. Essi non sono gli stessi. Le istanze sono HttpURLConnection
GC'd, il Socket
sottostante è riunito, a meno che non si chiama disconnect().
Altri suggerimenti
Dal Javadoc per HttpURLConnection (il corsivo è mio):
Ogni istanza è HttpURLConnection usato per fare un singola richiesta, ma la connessione di rete sottostante al server HTTP può essere trasparente condiviso da altre istanze. Chiamando il chiudi metodi () sul InputStream o OutputStream di un HttpURLConnection dopo una richiesta può liberare rete risorse associato a questa grado, ma non ha alcun effetto su qualunque condiviso connessione persistente. chiamata il metodo di disconnessione () possono vicino al sottostante presa se un persistente collegamento è inattivo in quel tempo.
Ho trovato che la connessione è infatti memorizzato nella cache quando l'InputStream è chiusa. Una volta che l'inputStream è stata chiusa la connessione sottostante è tamponata. L'oggetto HttpURLConnection è inutilizzabile per ulteriori richieste però, poiché l'oggetto è considerato ancora "connesso", cioè la sua boolean collegato è impostata su true e non viene cancellata quando la connessione viene reinserito nel buffer. Così ogni volta che un nuovo HttpURLConnection dovrebbe essere un'istanza per un nuovo post, ma la connessione TCP sottostante verrà riutilizzato, se non è scaduto. Così EJP risposta è stata la descrizione corretta. Può essere la sega comportamento che, (riutilizzo della connessione TCP) nonostante abbia chiamato in modo esplicito di disconnessione () è dovuta alla cache fatto dal sistema operativo? Non lo so. Spero che qualcuno che sa può spiegare. Grazie.
Come si fa "l'uso di forza HTTP1.0" usando il HttpURLConnection di JDK?
Secondo la sezione “Connessioni persistenti” del 1.5 guida di supporto Java per HTTP1.1 connessioni possono essere spenti o sull'uso del http.keepAlive
proprietà Java (di default è vero). Inoltre, la struttura http.maxConnections
java indica il numero massimo di (simultanee) connessioni per destinazione necessari per essere mantenute vive in un dato momento.
Pertanto un "uso forza di HTTP1.0" potrebbe essere applicato per l'intera applicazione contemporaneamente impostando la http.keepAlive
proprietà Java false.
Hmmh. I può essere manca qualcosa qui (poiché questa è una vecchia questione), ma per quanto ne so, ci sono 2 modi ben noti a forza di chiusura della connessione TCP sottostante:
- Forza l'utilizzo di HTTP 1.0 (1.1 connessioni persistenti introdotte) - questo come indicato dalla linea di richiesta HTTP
- Inviare 'connessione' intestazione con valore 'vicino'; questo costringerà la chiusura pure.
L'abbandono flussi causerà le connessioni TCP inattive. Il flusso di risposta deve essere letto completamente. Un'altra cosa che ho trascurato inizialmente, e hanno visto trascurato nella maggior parte delle risposte su questo argomento è dimenticare di affrontare il flusso di errore in caso di eccezioni. Codice simile a questo uno fisso delle mie applicazioni che non è stato liberando risorse correttamente:
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();
}
}
Il lettore di buffer non è strettamente necessario, l'ho scelto perché il mio caso d'uso necessario leggere una riga alla volta.
Vedi anche: http: // docs .oracle.com / JavaSE / 1.5.0 / docs / guide / net / http-keepalive.html