2011-01-16 11 views
19

Sto provando a caricare il test su un server Java aprendo un gran numero di connessioni socket al server, autenticando , chiudendo la connessione, quindi ripetendo. La mia app fa funzionare grande per un po 'ma alla fine ottengo:"java.net.BindException: Indirizzo già in uso" durante il tentativo di creazione rapida di Socket e distruzione per test di carico

java.net.BindException: Address already in use: connect

Secondo la documentazione che ho letto, la ragione di questo è che le prese chiuse occupano ancora l'indirizzo locale assegnato a loro per un periodo di tempo dopo la chiusura() è stato chiamato. Questo dipende dal sistema operativo ma può essere dell'ordine di minuti. Ho provato a chiamare setReuseAddress(true) sul socket con la speranza che il suo indirizzo fosse riutilizzabile immediatamente dopo che è stato chiamato close(). Purtroppo questo non sembra essere il caso.

Il mio codice per la creazione di socket è:

Socket socket = new Socket(); 
socket.setReuseAddress(true); 
socket.connect(new InetSocketAddress(m_host, m_port)); 

Ma ancora ottengo questo errore:

java.net.BindException: Address already in use: connect after awhile.

C'è un altro modo per realizzare quello che sto cercando di fare? Vorrei ad esempio aprire 100 prese, chiuderle tutte, aprire 200 prese, chiuderle tutte, aprire 300, ecc. Fino a un massimo di 2000 socket.

Qualsiasi aiuto sarebbe molto apprezzato!

+1

È il server o il client che genera l'eccezione? Accade dopo un numero consistente di connessioni? –

+1

Probabilmente è necessario modificare le impostazioni TCP della macchina, vedere http://docs.alfresco.com/4.0/topic/com.alfresco.enterprise.doc/tasks/alf-win-regedit.html –

risposta

15

Si sta esaurendo lo spazio delle porte in uscita aprendo così tante prese in uscita entro il tempo TIME_WAIT di due minuti. La prima domanda che dovresti porci è che rappresenta un test di carico realistico? Un vero cliente lo farà davvero? In caso contrario, è sufficiente rivedere la metodologia di test.

BTW SO_LINGER è il numero di secondi che l'applicazione attenderà durante close() per i dati da svuotare. Normalmente è zero.La porta si bloccherà comunque per l'intervallo TIME_WAIT se questa è la fine che ha emesso la chiusura. Questa non è la stessa cosa È possibile abusare dell'opzione SO_LINGER per correggere il problema. Tuttavia ciò causerà anche comportamenti eccezionali al pari e, di nuovo, questo non è lo scopo di un test.

+0

Hai ragione nel senso che nessun vero cliente aprirà così tante connessioni. Nella mia applicazione, i client reali apriranno solo 1 connessione TCP al server. Quello che sto cercando di fare è simulare i client reali e mi piacerebbe avere tanti client simulati in esecuzione sulla stessa macchina possibile. – bradforj287

+0

Anche la tua risposta mi ha aiutato! :-) Qualcosa che vorrei aggiungere qui è che se si utilizza il metodo setSoLinger(), causa problemi ai peer già connessi e talvolta vengono disconnessi! Non so davvero cosa stia causando questo comportamento, ma mi ci sono voluti 45 minuti per capirlo! – M2X

+0

@ M2X SO_LINGER off è il valore predefinito, il che fa sì che 'close()' si comporti come tutti noi ora e amiamo. Se si imposta 'on' e * con un timeout pari a zero, * causa 'close()' e 'shutdown()' per emettere un reset invece di una chiusura corretta. Non volevo nemmeno menzionarlo perché è un comportamento così indesiderabile. Se ci sono validi motivi per scherzare con SO_LINGER in una normale applicazione TCP/IP, devo ancora incontrarli ... in quasi trent'anni. – EJP

-1

Penso che si dovrebbe pianificare sulla porta che si desidera utilizzare per connettersi per essere in uso. Con questo intendo lo provare a per connettersi utilizzando la porta specificata. Se la connessione non riesce (o nel tuo caso genera un'eccezione), prova ad aprire la connessione usando il numero di porta successivo.

Provare a eseguire il wrapping dell'istruzione connect in un try/catch.

Ecco alcuni pseudo-codice che trasmette quello che penso funzionerà:

portNumber = x //where x is the first port number you will try 
numConnections = 200 // or however many connections you want to open 
while(numConnections > 0){ 
    try{ 
     connect(host, portNumber) 
     numConnections-- 
    }catch(){} 
    portNumber++ 
} 

Questo codice non copre casi d'angolo, come "ciò che accade quando tutte le porte sono in uso?"

+1

Questo non ha senso Sta cercando di connettersi a un servizio che sta ascoltando un numero di porta fisso, non uno che può essere incrementato, e il suo problema è lo spazio della porta locale, non lo spazio della porta remota. – EJP

1

Non utilizzare bind() ma setReuseAddress (true) è solo strano, spero che capiate le implicazioni di setReuseAddress (e il punto di). 100-2000 è non un gran numero di socket da aprire, tuttavia il server al quale si sta tentando di connettersi (poiché sembra lo stesso addr/port pair), può semplicemente rilasciarli con un normale backlog di 50.

Modifica: se è necessario aprire più socket rapidamente (ermm port scan?), Mi piacerebbe molto consigliamo vivamente di utilizzare NIO e connect()/finishConnect() + Selector. Aprire 1000 prese nello stesso thread è semplicemente lenta. Hai dimenticato di aver bisogno di finishConnect() in entrambi i casi nel tuo codice.

Problemi correlati