a scopo di test/di benchmarking, voglio scrivere un programma Java che fa i seguenti compiti in un ciclo:HttpURLConnection: BindException durante la creazione di molte connessioni
- caricare i dati via HTTP GET da un server
- (generare una risposta sulla base dei dati ricevuti - non è importante a questo punto)
- inviare la risposta tramite HTTP POST allo stesso server
questo ciclo viene eseguito su più thread allo stesso tempo .
Dopo l'avvio, il programma funziona correttamente per un breve periodo di tempo ed è in grado di eseguire ~ 300 cicli per thread al secondo (il server Web viene eseguito sulla stessa macchina). Ma dopo 5-7 secondi, ricevo BindException: Address already in use
.
Il riavvio del programma dopo un tempo di raffreddamento di 20-30 secondi comporta lo stesso comportamento; quando lo riavvio immediatamente senza aspettare, si blocca immediatamente ... quindi suppongo che potrebbe essere un problema con risorse associate.
È un approccio rapido e sporco utilizzando HttpURLConnection
. Le parti rilevanti:
ottenere i dati dal server web
public String fetchData() throws IOException {
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setUseCaches(false);
conn.setRequestMethod("GET");
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
conn.disconnect();
return response.toString();
}
invio la risposta
public void sendData(byte[] data) throws IOException {
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.setDoOutput(true);
OutputStream os = conn.getOutputStream();
os.write(data);
os.close();
conn.disconnect();
}
Chiamando entrambi i metodi all'interno del filo
@Override
public void run() {
while(true) {
try {
String data = fetchData();
String answer = // ... generating answer
sendData(answer.getBytes("UTF-8"));
} catch (IOException e) {
// ...
}
}
}
Non esiste un singolo oggetto URL condiviso tra thread: ogni thread ha una propria istanza URL (tuttavia, ogni istanza punta allo stesso indirizzo).
edit:
Ecco la traccia dello stack della prima eccezione che si verifica:
java.net.BindException: Address already in use: connect
at java.net.DualStackPlainSocketImpl.connect0(Native Method)
at java.net.DualStackPlainSocketImpl.socketConnect(Unknown Source)
at java.net.AbstractPlainSocketImpl.doConnect(Unknown Source)
at java.net.AbstractPlainSocketImpl.connectToAddress(Unknown Source)
at java.net.AbstractPlainSocketImpl.connect(Unknown Source)
at java.net.PlainSocketImpl.connect(Unknown Source)
at java.net.SocksSocketImpl.connect(Unknown Source)
at java.net.Socket.connect(Unknown Source)
at java.net.Socket.connect(Unknown Source)
at sun.net.NetworkClient.doConnect(Unknown Source)
at sun.net.www.http.HttpClient.openServer(Unknown Source)
at sun.net.www.http.HttpClient.openServer(Unknown Source)
at sun.net.www.http.HttpClient.<init>(Unknown Source)
at sun.net.www.http.HttpClient.New(Unknown Source)
at sun.net.www.http.HttpClient.New(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.plainConnect0(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.plainConnect(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.connect(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
at PayloadProcessor.fetchData(PayloadProcessor.java:66)
at PayloadProcessor.run(PayloadProcessor.java:32)
at java.lang.Thread.run(Unknown Source)
Essa si verifica nel metodo fetchdata alla seguente riga:
in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
Ho rimosso le chiamate a disconnect()
(come sottolineato da Aaron) - sfortunatamente, lo stesso problema esiste ancora.
Supponiamo tutto è chiuso in modo corretto (non so se questo è il caso qui, basta lasciare per scontato che) - potrebbe essere il caso che il programma è semplicemente troppo veloce? Ho trovato un altro post su StackOverflow, la "soluzione" era di aggiungere un semplice Thread.sleep - ma dal momento che è un punto di riferimento e dovrebbe funzionare il più velocemente possibile, non mi piace. In che modo gli strumenti di test del carico gestiscono questo problema?
Ho ridotto la quantità di thread a 1, anche se il problema si verifica.
Inserendo qui la traccia di stack completa dell'errore potrebbe essere utile. Ad ogni modo, la prima cosa che ti consiglierei è di racchiudere le invocazioni _disconnect_ in una clausola _finally_: Forse ci sono così tante eccezioni che le connessioni non vengono chiuse in modo propizio, causando una perdita. –
Grazie, ho aggiunto la traccia dello stack. Hai ragione, c'erano davvero molte eccezioni - ma a scopo di debug, ora termino il programma dopo che la prima eccezione si è sollevata (non mostrata nel codice sopra) e continua ad avere lo stesso problema. La prima eccezione è già una BindException. – ceran
Si prega di aggiungere i risultati del comando 'netstat -anpt | grep 'o il suo analogo nel tuo sistema operativo. –
user1516873