我没想到 Bash 支持这么多高级功能!我开始开发一个简单的网络程序来尝试使用我发现的一些东西。我的特定程序是一个完全用 Bash 编写的基本 Redis 客户端。目前,我可以执行以下操作:
redis_command -c "ping" redis{001..100}:{6379..6400}
它将向所有实例(大约 2100 个)发送“ping”命令并返回结果。我目前正在串行发送“ping”命令,但我认为可以通过并行执行所有初始套接字创建来加速我的程序。我在有/没有优化的情况下测试了我的程序,并意识到我的优化实际上减慢了速度。优化效果如下:
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
通常, get_socket() 函数本身就可以很好地工作。如果我需要向特定服务器发送命令,我会提前调用 get_socket(),并将 FD 传递给另一个实际发送命令并解析响应的函数。在预连接场景中,我通过 & 在后台调用 get_socket。由于 get_socket()& 在单独的进程中运行,因此创建的 FD 在调用进程中不可用/不可访问,因此我的优化毫无用处。
有没有什么方法可以在 bash 中发送套接字,或者有其他方法可以在不使用单独进程的情况下并行化我的连接?
答案1
不能/dev/tcp/x/y
直接使用,但您可以使用管道与后台启动的进程进行通信,以连接 TCP 套接字并传输数据。
就像是
coproc hostA {
exec {fd}<> /dev/tcp/127.0.0.1/80
cat <&$fd & cat >&$fd
}
# same for hostB...
echo -e 'HEAD / HTTP/1.0\r\n\r' >&${hostA[1]}
cat <&${hostA[0]}
无论如何,当您最终运行两个cat
命令时,您最好不使用/dev/tcp
(并不总是启用)并使用例如 socat:
coproc hostA { socat - tcp:localhost:80; }
或者,您可以使用命名管道来删除对 bash 的依赖:
mkfifo hostA.in hostA.out
socat - tcp:localhost:80 < hostA.in > hostA.out &