2011-01-16 11 views
19

Estoy intentando cargar la prueba de un servidor Java abriendo una gran cantidad de conexiones de socket al servidor, autenticando , cerrando la conexión, luego repitiendo. Mi aplicación se ejecuta muy bien por un tiempo, pero finalmente me sale:"java.net.BindException: dirección ya en uso" al intentar hacer una creación y destrucción rápida de socket para pruebas de carga

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

De acuerdo con la documentación que he leído, la razón de esto es que las tomas cerradas siguen ocupando la dirección local asignada a ellos por un período de tiempo después del cierre() era llamado. Esto depende del sistema operativo, pero puede ser del orden de minutos. Intenté llamar al setReuseAddress(true) en el socket con la esperanza de que su dirección sería reutilizable inmediatamente después de llamar al close(). Lamentablemente, este no parece ser el caso.

Mi código para la creación de socket es:

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

Pero sigo teniendo este error:

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

¿Hay alguna otra manera de lograr lo que estoy tratando de hacer? Me gustaría, por ejemplo, abrir 100 tomas, cerrarlas todas, abrir 200 tomas, cerrarlas todas, abrir 300, etc. hasta un máximo de 2000 tomas.

¡Cualquier ayuda sería muy apreciada!

+1

¿Es el servidor o el cliente el que lanza la excepción? ¿Sucede después de una cantidad constante de conexiones? –

+1

Probablemente necesite cambiar la configuración TCP de la máquina, consulte http://docs.alfresco.com/4.0/topic/com.alfresco.enterprise.doc/tasks/alf-win-regedit.html –

Respuesta

15

Está agotando el espacio de los puertos de salida abriendo muchos sockets de salida dentro del período TIME_WAIT de dos minutos. La primera pregunta que debes hacerte es, ¿representa esto una prueba de carga realista? ¿Realmente un verdadero cliente va a hacer eso? Si no, solo necesita revisar su metodología de prueba.

BTW SO_LINGER es el número de segundos que la aplicación esperará durante el cierre() para que los datos se descarguen. Normalmente es cero.El puerto se mantendrá durante el intervalo TIME_WAIT de todos modos si este es el final que emitió el cierre. Esto no es lo mismo. Es posible abusar de la opción SO_LINGER para corregir el problema. Sin embargo, eso también causará un comportamiento excepcional en el par y, nuevamente, este no es el propósito de una prueba.

+0

Tiene razón en que ningún cliente real va a abrir tantas conexiones. En mi aplicación, los clientes reales solo abrirán 1 conexión TCP al servidor. Lo que trato de hacer es simular clientes reales y me gustaría tener tantos clientes simulados corriendo en la misma máquina como sea posible. – bradforj287

+0

¡Tu respuesta también me ayudó! :-) Algo que quisiera agregar aquí es que si usas el método setSoLinger(), causa problemas a los compañeros ya conectados y a veces también se desconectan. Realmente no sé lo que está causando este comportamiento, pero me llevó unos buenos 45 minutos averiguarlo. – M2X

+0

@ M2X SO_LINGER desactivado es el valor predeterminado, lo que hace que 'close()' se comporte como todos ahora y nos encanta. Si lo configura 'on' y * con un timeout cero, * causa 'close()' y 'shutdown()' para emitir un restablecimiento en lugar de un cierre apropiado. Ni siquiera quería mencionar esto porque es un comportamiento tan indeseable. Si hay alguna razón válida para meterse con SO_LINGER en una aplicación TCP/IP normal, aún no los he encontrado ... en casi treinta años. – EJP

-1

Creo que debe planificar el puerto que desea utilizar para conectarse y estar en uso. Con esto me refiero a intente para conectarse usando el puerto dado. Si la conexión falla (o en su caso arroja una excepción), intente abrir la conexión utilizando el siguiente número de puerto.

Intente ajustar la declaración connect en un try/catch.

He aquí algunos pseudo-código que transmite lo que creo que va a trabajar:

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++ 
} 

Este código no cubre los casos de esquina como "lo que sucede cuando todos los puertos están en uso?"

+1

Esto no significa ningún sentido. Está intentando conectarse a un servicio que está escuchando a un número de puerto fijo, no uno que puede incrementarse, y su problema es el espacio del puerto local, no el espacio del puerto remoto. – EJP

1

No usar bind() pero setReuseAddress (true) es simplemente extraño, espero que entiendas las implicaciones de setReuseAddress (y el punto de). 100-2000 es no un gran número de sockets para abrir; sin embargo, el servidor al que está intentando conectarse (dado que tiene el mismo par addr/puerto), puede soltarlos con un retraso acumulado normal de 50.

Editar: si necesita abrir varias tomas rápidamente (¿escaneo de puertos ermm?), Me gustaría muy recomendar encarecidamente utilizar NIO y connect()/finishConnect() + Selector. La apertura de 1000 sockets en el mismo hilo es simplemente lenta. Olvidó que puede necesitar finishConnect() de cualquier manera en su código.

Cuestiones relacionadas