¡No tenía idea de que Bash admitiera tantas funciones avanzadas! Empecé a trabajar en un programa de red simple para probar y usar algunas de estas cosas que encontré. Mi programa particular es un cliente redis básico escrito completamente en Bash. Actualmente, puedo hacer algo como lo siguiente:
redis_command -c "ping" redis{001..100}:{6379..6400}
Enviará el comando "ping" a todas las instancias (alrededor de 2100) y devolverá los resultados. Actualmente estoy enviando el comando "ping" en serie, pero pensé que podría acelerar mi programa haciendo toda la creación del socket inicial en paralelo. Probé mi programa con/sin la optimización y me di cuenta de que mi optimización en realidad ralentizaba las cosas. Así es como se ve la optimización:
declare -A SOCKETS
function get_socket {
# args: <hostname> <port>
# returns: the socket number, or failure return code
# verify args
if [[ -z "${1}" ]]; then
return 1
fi
if [[ -z "${2}" ]]; then
return 1
fi
local HOSTPORT="${1}:${2}"
if [[ -z ${SOCKETS[${HOSTPORT}]} ]]; then
exec {fd}<>/dev/tcp/${1}/${2}
SOCKETS[${HOSTPORT}]=${fd}
RES=${fd}
else
RES="${SOCKETS[${HOSTPORT}]}"
fi
}
if [[ ${PRECONNECT} -eq 1 ]]; then
echo -n "Pre-connecting to ${#HOSTS[@]} instances... " >&2
for HOST in ${HOSTS[@]}; do
get_socket "${HOST%%:*}" "${HOST##*:}" &
PIDS+=($!)
done
# make sure all of our async connections finished before starting
# TODO, check for errors
for PID in ${PIDS[@]}; do
wait ${PID}
done
echo "done" >&2
fi
Normalmente, la función get_socket() por sí sola funciona muy bien. Si alguna vez necesito enviar un comando a un servidor en particular, llamo a get_socket() con anticipación y paso el FD a otra función que realmente envía el comando y analiza la respuesta. En el escenario previo a la conexión, llamo a get_socket en segundo plano a través de &. Dado que get_socket()&se ejecuta en un proceso separado, el FD creado no está disponible/accesible en el proceso de llamada, por lo que mi optimización es inútil.
¿Hay alguna forma de enviar sockets en bash, o alguna otra forma en la que pueda paralelizar mis conexiones sin usar un proceso separado?
Respuesta aceptada:
No con /dev/tcp/x/y
directamente, pero podría usar canalizaciones para comunicarse con procesos que se inician en segundo plano para conectar los sockets TCP y transferir datos.
Algo como
coproc hostA {
exec {fd}<> /dev/tcp/127.0.0.1/80
cat <&$fd & cat >&$fd
}
# same for hostB...
echo -e 'HEAD / HTTP/1.0rnr' >&${hostA[1]}
cat <&${hostA[0]}
Como terminas ejecutando dos cat
comandos de todos modos, también podría prescindir de /dev/tcp
(que no siempre está habilitado) y use, por ejemplo, socat:
coproc hostA { socat - tcp:localhost:80; }
O bien, puede eliminar la dependencia de bash mediante el uso de canalizaciones con nombre:
mkfifo hostA.in hostA.out
socat - tcp:localhost:80 < hostA.in > hostA.out &