Netušil jsem, že Bash podporuje tolik pokročilých funkcí! Začal jsem pracovat na jednoduchém síťovém programu, abych vyzkoušel a použil některé z těchto věcí, které jsem našel. Můj konkrétní program je základní klient redis napsaný kompletně v Bash. V současné době mohu udělat něco jako následující:
redis_command -c "ping" redis{001..100}:{6379..6400}
Odešle příkaz „ping“ všem instancím (asi 2100) a vrátí výsledky. V současné době odesílám příkaz „ping“ sériově, ale myslel jsem, že bych mohl urychlit svůj program tím, že bych všechny počáteční vytváření soketu provedl paralelně. Testoval jsem svůj program s/bez optimalizace a uvědomil jsem si, že moje optimalizace ve skutečnosti věci zpomalila. Optimalizace vypadá takto:
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
Normálně funguje funkce get_socket() sama o sobě skvěle. Pokud někdy potřebuji odeslat příkaz na konkrétní server, zavolám předem get_socket() a předám FD jiné funkci, která příkaz skutečně odešle a analyzuje odpověď. Ve scénáři předběžného připojení volám get_socket na pozadí přes &. Vzhledem k tomu, že get_socket()&běží v samostatném procesu, vytvořený FD není dostupný/přístupný v procesu volání, takže moje optimalizace je k ničemu.
Existuje nějaký způsob, jak odeslat sokety v bash, nebo nějaký jiný způsob, jak mohu paralelizovat svá připojení bez použití samostatného procesu?
Přijatá odpověď:
Ne s /dev/tcp/x/y
přímo, ale můžete použít roury ke komunikaci s procesy, které jsou spuštěny na pozadí pro připojení TCP soketů a přenos dat.
Něco jako
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]}
Jak skončíte spuštěním dvou cat
příkazů se stejně můžete obejít bez /dev/tcp
(což není vždy povoleno) a použijte například socat:
coproc hostA { socat - tcp:localhost:80; }
Nebo můžete závislost na bash odstranit pomocí pojmenovaných kanálů:
mkfifo hostA.in hostA.out
socat - tcp:localhost:80 < hostA.in > hostA.out &