No bash, posso assíncrono abrir soquetes e usá-los depois?

4

Eu não tinha ideia de que o Bash suportava tantos recursos avançados! Comecei a trabalhar em um programa de rede simples para tentar usar algumas dessas coisas que encontrei. Meu programa em particular é um cliente básico de redis escrito completamente em Bash. Atualmente, posso fazer algo como o seguinte:

redis_command -c "ping" redis{001..100}:{6379..6400}

Ele enviará o comando "ping" para todas as instâncias (aproximadamente 2100) e retornará os resultados. Atualmente, estou enviando o comando "ping" em série, mas achei que poderia acelerar meu programa fazendo toda a criação de soquete inicial em paralelo. Eu testei meu programa com / sem a otimização e percebi que minha otimização na verdade atrasava as coisas. Veja como a otimização parece:

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, a função get_socket () por si só funciona muito bem. Se eu precisar enviar um comando para um servidor específico, chamo get_socket () antecipadamente e transmito o FD para outra função que realmente envia o comando e analisa a resposta. No cenário de pré-conexão, estou chamando get_socket em segundo plano via &. Desde get_socket () e amp; executado em um processo separado, o FD criado não está disponível / acessível no processo de chamada, então minha otimização é inútil.

Existe alguma maneira de enviar sockets no bash, ou de alguma outra maneira que eu possa paralelizar minhas conexões sem usar um processo separado?

    
por Michael Spiegle 15.02.2013 / 23:09

1 resposta

2

Não com /dev/tcp/x/y diretamente, mas você pode usar pipes para se comunicar com processos iniciados em segundo plano para conectar os soquetes TCP e transferir dados.

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.0\r\n\r' >&${hostA[1]}
cat <&${hostA[0]}

Como você acaba executando dois comandos cat de qualquer forma, você pode ficar sem /dev/tcp (que nem sempre está ativado) e usar por exemplo socat:

coproc hostA { socat - tcp:localhost:80; }

Ou, você pode remover a dependência do bash usando pipes nomeados:

mkfifo hostA.in hostA.out
socat - tcp:localhost:80 < hostA.in > hostA.out &
    
por 15.02.2013 / 23:48