La herramienta Port4Me :
Encuentra un puerto TCP gratuito en [1024,65535] que el usuario puede abrir
está diseñado para funcionar en entornos de usuarios múltiples
ofrece diferentes usuarios, diferentes puertos
le da al usuario el mismo puerto a lo largo del tiempo con alta probabilidad
ofrece diferentes puertos para diferentes herramientas de software
no requiere configuración
se puede reproducir perfectamente en todos los sistemas operativos y en todos los lenguajes de programación comunes
Disponible para Bash, Python y R
Hay muchas herramientas para identificar un puerto TCP gratuito, donde la mayoría de ellas devuelven un puerto aleatorio. Aunque funciona técnicamente, podría agregar un poco de fricción si el usuario debe ingresar un nuevo número de puerto aleatorio cada vez que necesite usar una herramienta específica.
Por el contrario, los intentos de Port4Me , con alta probabilidad, para proporcionar al usuario el mismo puerto cada vez, incluso cuando se usan en diferentes días. Logra esto escaneando la misma secuencia pseudo-aleatorio determinista de puertos y devuelve el primer puerto libre detectado. Cada usuario obtiene su propia secuencia de puerto aleatorio, reduciendo el riesgo de que dos usuarios soliciten el mismo puerto. La aleatoriedad se inicia con una semilla aleatoria que es una función del nombre del usuario ( USER ) y, opcionalmente, el nombre del software donde usamos el puerto.
El algoritmo Port4Me se puede implementar en los lenguajes de programación más conocidos, produciendo una secuenciación perfectamente reproducible independientemente del lenguaje de implementación.
Suponiendo que nos iniciamos sesión como usuario alice en un shell bash, llamar port4me sin argumentos nos da un puerto gratuito:
{alice}$ port4me
30845Como veremos más adelante, es probable que cada usuario en el sistema obtenga su propio puerto único. Debido a esto, se puede usar para especificar un puerto que alguna herramienta de software debe usar, por ejemplo,
{alice}$ jupyter notebook --port " $( port4me ) " Mientras este puerto esté disponible, alice siempre obtendrá el mismo puerto en las sesiones de shell y con el tiempo. Por ejemplo, si regresan la próxima semana y vuelven a intentarlo, es probable que aún obtengan:
{alice}$ port4me
30845
{alice}$ port4me
30845Sin embargo, si el puerto 30845 ya está ocupado, se considera el siguiente puerto en la secuencia pseudo-aleatoria, por ejemplo,
{alice}$ port4me
19654Para ver los primeros cinco puertos escaneados, ejecute:
{alice}$ port4me --list=5
30845
19654
32310
63992
15273 Esta secuencia aleatoria se inicia mediante una semilla aleatoria que se puede establecer a través del hásido de una cadena de semillas. Por defecto, se basa en el nombre del usuario actual (por ejemplo, variable de entorno $USER ). Por ejemplo, cuando el usuario bob usa la herramienta port4me , ven otro conjunto de puertos escaneados:
{bob}$ port4me --list=5
54242
4930
42139
14723
55707 Para fines de prueba y demostración, se puede emular a otro usuario especificando la --user , por ejemplo,
{alice}$ port4me
30845
{alice}$ port4me --user=bob
54242
{alice}$ port4me --user=carol
34307 A veces, a un usuario le gustaría usar dos o más puertos al mismo tiempo, por ejemplo, un puerto para el servidor RSTUDIO y otro para Jupyter Notebook. En tal caso, pueden especificar la opción --tool , que da como resultado una secuencia de puerto que es exclusiva tanto para el usuario como para la herramienta. Por ejemplo,
{alice}$ port4me
30845
{alice}$ port4me --tool=rstudio
22486
{alice}$ port4me --tool=jupyter-notebook
29525 Por conveniencia, si la primera opción no tiene nombre, entonces se supone que especifica la opción --tool . Esto significa que también podemos usar el siguiente formulario de clasificación:
{alice}$ port4me jupyter-notebook
47467Esto nos permite obtener diferentes puertos para diferentes herramientas de software, por ejemplo,
{alice}$ rserver --www-port " $( port4me rstudio ) "y
{alice}$ jupyter notebook --port " $( port4me jupyter-notebook ) " Dado que hay un conjunto limitado de puertos disponibles (1024-65535), siempre existe el riesgo de que otro proceso ocupe un puerto dado. Cuantos más usuarios hay en la misma máquina, mayor será el riesgo que esto suceda. Si un usuario tiene mala suerte, podría experimentar esto con frecuencia. Por ejemplo, alice podría encontrar que el primer puerto (30845) funciona solo una de 10 veces, el segundo puerto (19654) funciona 99 100 veces, y el tercero (32310) funciona raramente. Si es así, pueden optar por excluir los puertos que tienen más probabilidades de estar ocupados especificándolos como valores separados por comas a través de la opción: --exclude , por ejemplo,
{alice}$ port4me --exclude=30845,32310
19654 Una alternativa para especificarlos a través de una opción de línea de comandos es especificarlos a través de la variable de entorno PORT4ME_EXCLUDE , EG
{alice}$ PORT4ME_EXCLUDE=30845,32310 port4me
19654Para establecer esto de forma permanente, agregue:
# # port4me customization
# # https://github.com/HenrikBengtsson/port4me
PORT4ME_EXCLUDE=30845,32310
export PORT4ME_EXCLUDE al script de inicio de shell, por ejemplo, ~/.bashrc .
Esto aumenta las posibilidades de que el usuario termine con el mismo puerto a lo largo del tiempo, lo cual es conveniente, porque puede reutilizar la misma llamada, que está disponible en el historial de la línea de comandos, cada vez sin tener que cambiar el parámetro del puerto.
La variable de entorno PORT4ME_EXCLUDE está destinada a ser utilizada por el usuario individual. Para especificar un conjunto de puertos que se excluirán independientemente del usuario, establezca PORT4ME_EXCLUDE_SITE . Por ejemplo, el administrador de sistemas puede optar por excluir un conjunto adicional de puertos agregando lo siguiente a archivar /etc/profile.d/port4me.sh :
# # port4me: always exclude commonly used ports
# # https://github.com/HenrikBengtsson/port4me
PORT4ME_EXCLUDE_SITE=
# # MySQL
PORT4ME_EXCLUDE_SITE= $PORT4ME_EXCLUDE_SITE ,3306
# # ZeroMQ
PORT4ME_EXCLUDE_SITE= $PORT4ME_EXCLUDE_SITE ,5670
# # Redis
PORT4ME_EXCLUDE_SITE= $PORT4ME_EXCLUDE_SITE ,6379
# # Jupyter
PORT4ME_EXCLUDE_SITE= $PORT4ME_EXCLUDE_SITE ,8888
export PORT4ME_EXCLUDE_SITE Además de los puertos excluidos a través de mecanismos anteriores, Port4Me excluye los puertos que son considerados inseguros por los navegadores web Chrome y Firefox. Este comportamiento puede ser controlado por la variable de entorno PORT4ME_EXCLUDE_UNSAFE , que predeterminada {chrome},{firefox} . Token {chrome} se expande al valor de PORT4ME_EXCLUDE_UNSAFE_CHROME , que predetermina el conjunto de puertos que Chrome bloquea, y {firefox} se expande al valor de PORT4ME_EXCLUDE_UNSAFE_FIREFOX , que predeterminados a los puertos de Firefox bloquea.
Al análoga, para excluir un conjunto de puertos, se puede limitar el conjunto de puertos que se escanearán especificando la opción de línea de comandos --include , por ejemplo
{alice}$ port4me --include=2000-2123,4321,10000-10999
10451 donde el valor predeterminado corresponde a --include=1024-65535 . Análogamente a --exclude , --include se puede especificar a través de variables de entorno PORT4ME_INCLUDE y PORT4ME_INCLUDE_SITE .
Además de escanear la secuencia de puerto pseudo-aleatorio específica del usuario para un puerto libre, es posible considerar también un conjunto predefinido de puertos antes de los aleatorios especificando la opción de línea de comandos --prepend , EG
{alice}$ port4me --prepend=4321,11001 --list=5
4321
11001
30845
19654
32310 Una alternativa para especificarlos a través de una opción de línea de comandos es especificarlos a través de la variable de entorno PORT4ME_PREPEND , EG
{alice}$ PORT4ME_PREPEND=4321,11001 port4me --list=5
4321
11001
30845
19654
32310 La variable de entorno PORT4ME_PREPEND está destinada a ser utilizada por el usuario individual. Para especificar un conjunto de puertos que se prependan independientemente del usuario, establezca PORT4ME_PREPEND_SITE .
Todas las implementaciones de Port4Me salen el puerto identificado a la salida estándar (STDOUT). Esto facilita la captura mediante métodos de shell estándar, por ejemplo, port="$(port4me)" . Si desea ver qué número de puerto se generó, use tee para enviar el puerto también al error estándar (STDERR), que se puede ver en el terminal. Por ejemplo,
{alice}$ jupyter notebook --port " $( port4me --tool=jupyter-notebook | tee /dev/stderr ) "
29525Para instalar la versión bash de Portme , haz:
VERSION=0.7.1
curl -L -O https://github.com/HenrikBengtsson/port4me/archive/refs/tags/ " ${VERSION} .tar.gz "
tar -x -f " ${VERSION} .tar.gz "
export PREFIX=/path/to/port4me/ # # must be an absolute path to a folder
(cd " port4me- ${VERSION} /bash " ; make install)Luego ejecutarlo como:
$ export PATH=/path/to/port4me/bin: $PATH
$ port4me --version
0.7.1Para instalar el paquete R Portme , que está disponible en CRAN, llame a lo siguiente desde R:
install.packages( " port4me " )Para probarlo, llame:
> port4me :: port4me( " jupyter-notebook " )
[ 1 ] 47467o
$ Rscript -e port4me::port4me jupyter-notebook
29525El paquete Python Port4me está disponible Pypi. Para instalar el paquete Python Portme en su biblioteca personal de paquetes Python, llame a lo siguiente desde la línea de comando:
$ pip install --user port4me Para instalarlo en un entorno virtual de Python, la opción Drop --user .
Para probarlo, llame:
>>> from port4me import port4me
>>> port4me( " jupyter-notebook " )
29525o
$ python -m port4me --tool=jupyter-notebook
29525 Debería ser posible implementar el algoritmo utilizando aritmética entera sin firmar de 32 bits. No se debe suponer que el entero representado más grande puede exceder
La secuencia de puerto pseudo-aleatomizada debe probar puertos de manera uniforme
Como mínimo, debería ser posible implementar el algoritmo en Vanilla Sh*, CSH, Bash, C, C ++, Fortran, Lua, Python, R y Ruby, sin necesidad de paquetes complementarios más allá de lo que está disponible de su distribución central. (*) Las conchas que no admiten la aritmética entera pueden usar herramientas como expr , dc , bc y awk para estos cálculos.
Todos los lenguajes de programación deben producir exactamente las mismas secuencias de puertos pseudo-aleatorios dadas la misma semilla aleatoria.
Las implementaciones deben estar escritas de tal manera que funcionen también cuando se obtienen, o se copian en el código fuente en otro lugar, por ejemplo, en los scripts R y Python.
El puerto libre identificado debe emitirse a la salida estándar (stDout) como dígitos solo, sin ningún símbolo de prefijo o sufijo.
El usuario debe poder excluir un conjunto predefinido de puertos especificando la variable de entorno PORT4ME_EXCLUDE , por ejemplo, PORT4ME_EXCLUDE=8080,4321 .
El administrador del sistema debe poder especificar un conjunto predefinido de puertos que se excluyan especificando la variable de entorno PORT4ME_EXCLUDE_SITE , por ejemplo, PORT4ME_EXCLUDE_SITE=8080,4321 . Esto funciona complementario a PORT4ME_EXCLUDE .
El usuario debe poder omitir un cierto número de puertos aleatorios a su voluntad especificando el entorno variable PORT4ME_SKIP , por ejemplo, PORT4ME_SKIP=5 . El valor predeterminado es no omitir, que corresponde a PORT4ME_SKIP=0 . El omisión debe aplicarse después de que los puertos estén excluyendo por PORT4ME_EXCLUDE y PORT4ME_EXCLUDE_SITE .
Las nuevas implementaciones deben reproducir perfectamente las secuencias de puertos producidas por implementaciones ya existentes.
Se utilizará un generador congruencial lineal (LCG) para generar la secuencia de puertos pseudo-aleatorio
la próxima semilla,
El algoritmo LCG no debe suponer que la semilla de LCG actual está dentro
El algoritmo LCG puede producir la misma semilla de salida que la semilla de entrada, que puede ocurrir cuando la semilla es
Los parámetros LCG deben ser
Esto requiere solo aritmética entera de 32 bits, porque
Si la semilla inicial es
Se utilizará un hashcode de una cadena entera de 32 bits para generar un entero en
El hashcode de cadena se usa como semilla LCG inicial:
la semilla de LCG debe estar en
dado el hashcode