Desde hace tiempo usamos ActiveMQ en el curro, embebido en Spring. Una cosa que nos pasaba esporádicamente en nuestros ordenadores de desarrollo es que ActiveMQ no arrancaba. Daba error de que su puerto por defecto, el 61616 ya estaba en uso. Vamos, el típico error
Cannot bind port 61616: Address already in use!
Por más que hacías un netstat para ver si el puerto realmente estaba en uso, no había nadie utilizando dicho puerto. Intentos sucesivos de arrancar la aplicación fallaban con el mismo error. Y reiniciando el ordenador entero, solía arreglarse y ya no fallaba…. hasta que aleatoriamente y de forma bastante esporádica, en otro arranque del PC, ya no funcionaba.
Así que la última vez que me pasó, hace un par de días y tras reiniciar el ordenador ver que el problema no se arreglaba, decidí investigar en serio. Costó algo encontrar la información, pero ahí va.
La culpa es de los ephemeral ports
Parece ser que los sistemas operativos, tras su arranque, se reservan una serie de puertos para establecer las comunicaciones y no dejan usarlos aunque no los estén usando ellos. Suelen ser bloques seguidos de 10 puertos dentro de un rango grande. Estos puertos son los que se conocen como ephemeral ports.
En el caso de Windows, mi caso, elige esos puertos de forma aleatoria en cada arranque dentro del rango 49152-65535. Y el puerto 61616 de ActiveMQ está ahí dentro, así que es candidato a que en algún arranque el sistema operativo lo pille y ActiveMQ no arranque. Linux usa otro rango, pero también hace algo parecido.
El comando windows
netsh int ip show excludedportrange protocol=tcp
nos muestra qué puertos ha pillado el sistema operativo y no podremos usar, aunque estén libres. La salida de este comando podría parecerse a la sigiuiente
Puerto de inicio Puerto final
———- ——–
80 80
8005 8005
21112 21112
50000 50059 *
50060 50159
61510 61609
61610 61709 <– Justo el 61616 cae en este rango
61910 62009
62010 62109
62110 62209
63442 63541
- – Exclusiones de puertos administrados
Hay varias soluciones a este problema. Una, desde luego evidente, es configurar ActiveMQ para que use otro puerto fuera del rango 49152-65535 de puertos que podría querer reservar Windows
Tenemos otra opción para solucionar el problema en el momento que nos ocurra, sin necesidad de reiniciar el ordenador, pero desde luego, no es la mejor solución. La comento por si fuera de utilidad en algún momento.
Desde un terminal de comandos windows con permisos de super usuario, sería ejecutar los siguientes comandos
net stop winnat
Arrancar nuestra aplicación
net start winnat
net stop winnat para el servicio Windows Nat Driver (winnat), que es el que suele reservar esos puertos. Parando el servicio, se liberan los puertos. Podemos entonces arrancar nuestra aplicación sin problemas. Luego volvemos a arrancar el servicio winnat que pillará otros puertos que estén libres.
La solución más permanente, si no puedes cambiar en tu aplicación el puerto de ActiveMQ (o el que te esté dando problemas), es reservar tú ese puerto para que windows no lo reserve en el arranque. Para ello, con un terminal de comandos de windows con permiso de super usuario puedes ejecutar el comando
netsh int ipv4 add excludedportrange protocol=tcp startport=61616 numberofports=1
Eso reserva 1 puerto (numberofports) a partir del puerto 61616 (starport). Puedes reservar un bloque algo más grande por seguridad, por ejemplo, 20 puertos a partir del 61610 o lo que consideres. Esta orden permanece en arranques sucesivos del PC, por lo que no tienes que ejecutarla cada vez.
Para ejecutar este comando es importante que esos puertos estén libres en ese momento. Si no lo están, tendrías que parar temporalmente winnat como has visto antes.
Los puertos que hayas reservado aparecen en el listado anterior con un * detrás, como en el primero ejemplo es el rango 50000 a 50059.