GNU/Linux >> Tutoriels Linux >  >> Linux

Dans Bash, puis-je ouvrir des sockets de manière asynchrone et les utiliser plus tard ?

Je ne savais pas que Bash supportait autant de fonctionnalités avancées ! J'ai commencé à travailler sur un programme réseau simple pour essayer d'utiliser certaines de ces choses que j'ai trouvées. Mon programme particulier est un client redis de base entièrement écrit en Bash. Actuellement, je peux faire quelque chose comme ceci :

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

Il enverra la commande "ping" à toutes les instances (environ 2100) et renverra les résultats. J'envoie actuellement la commande "ping" en série, mais je pensais pouvoir accélérer mon programme en effectuant toute la création initiale du socket en parallèle. J'ai testé mon programme avec/sans l'optimisation, et j'ai réalisé que mon optimisation ralentissait en fait les choses. Voici à quoi ressemble l'optimisation :

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

Normalement, la fonction get_socket() seule fonctionne très bien. Si jamais j'ai besoin d'envoyer une commande à un serveur particulier, j'appelle get_socket() à l'avance et je transmets le FD à une autre fonction qui envoie réellement la commande et analyse la réponse. Dans le scénario de pré-connexion, j'appelle get_socket en arrière-plan via &. Étant donné que get_socket()&s'exécute dans un processus séparé, le FD créé n'est pas disponible/accessible dans le processus d'appel, donc mon optimisation est inutile.

Existe-t-il un moyen d'envoyer des sockets dans bash ou une autre manière de paralléliser mes connexions sans utiliser de processus séparé ?

Réponse acceptée :

Pas avec /dev/tcp/x/y directement, mais vous pouvez utiliser des canaux pour communiquer avec des processus démarrés en arrière-plan pour connecter les sockets TCP et transférer des données.

Quelque chose comme

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]}

Lorsque vous finissez par exécuter deux cat de toute façon, autant se passer de /dev/tcp (qui n'est pas toujours activé) et utilisez par exemple socat :

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

Ou, vous pouvez supprimer la dépendance à bash en utilisant des canaux nommés :

mkfifo hostA.in hostA.out
socat - tcp:localhost:80 < hostA.in > hostA.out &

Linux
  1. Comment utiliser la commande d'arrêt de Linux, redémarrages planifiés et immédiats

  2. Utilisez grep pour rechercher du contenu dans des fichiers et les déplacer s'ils correspondent

  3. Comment puis-je utiliser des commandes aliasées avec xargs ?

  4. Pourquoi eval devrait-il être évité dans Bash et que dois-je utiliser à la place ?

  5. Essayer d'utiliser bash sous Windows et n'a reçu aucun message de distributions installées

Comprendre les chemins de fichiers et comment les utiliser sous Linux

Comment créer des rôles Ansible et les utiliser dans Playbook

Comment utiliser bash if -z et if -n pour tester des chaînes sous Linux

Puis-je utiliser Calibre pour commander et écouter des livres audio ?

Schémas de couleurs dans Vim :comment les modifier et les utiliser

Bash Scripting Part6 - Créer et utiliser des fonctions Bash