Quelle est la différence entre ces quatre commandes (fifo, substitution de processus, redirection…)

8

Mon objectif est de créer un serveur d'écho simple en utilisant ncet un seul fifo. Je ne cherche pas la meilleure façon de le faire, j'essaie simplement de comprendre la sémantique des commandes suivantes (quand se produit fork, pourquoi, qu'est-ce que cela change, pourquoi les commandes se comportent différemment ...).

J'utilise Bash, donc je ne sais pas si toutes les commandes ne fonctionnent pas avec un Posix shou zsh, ksh...

Voici les quatre commandes que je mentionne dans le titre (en supposant que je l'ai déjà fait mkfifo fifo):

cat fifo | nc -l localhost 8888 > fifo
exec 3<> fifo && nc -l localhost 8888 <&3 >&3 && exec 3>&-
nc -l localhost 8888 <(cat fifo) > fifo
nc -l localhost 8888 < fifo > fifo

Maintenant, je m'attendrais à ce que les 4 commandes fassent la même chose, au moins les deux dernières fassent la même chose.

  1. La première commande se comporte comme prévu, un simple serveur d'écho qui s'arrête lorsque le client ferme la connexion.
  2. Se comporte comme 1.
  3. Je peux me connecter au serveur, envoyer des données, mais je ne reçois jamais rien en retour. Lorsque je ferme la connexion client, le serveur s'arrête.
  4. Impossible de se connecter au serveur, le serveur écoute indéfiniment.
foo
la source

Réponses:

8

La clé ici est que l'ouverture d'un FIFO est une opération de blocage. Le openseul retourne une fois que les deux extrémités sont connectées, c'est-à-dire une fois que le fifo est ouvert pour la lecture et l'écriture.

homme fifo (7)

Normally, opening the FIFO blocks until the other end is opened also.

Dans le premier cas, le shell bifurque pour exécuter le pipeline, donc l'ouverture du fifo pour la lecture ( cat fifo) et l'ouverture du fifo pour l'écriture ( > fifo) se produisent dans des processus séparés, donc indépendamment.

Dans le deuxième cas, l'ouverture pour la lecture et l'ouverture pour l'écriture ( 3<>fifo) se produisent en une seule étape.

Dans le 3ème cas, se <(cat fifo)développe en un nom de fichier, par exemple /dev/fd/42. C'est comme si vous couriez nc -l localhost 8888 /dev/fd/42 > fifo. Vous avez besoin d'un supplément <pour qu'il soit équivalent, par exemple nc -l localhost 8888 < <(cat fifo) > fifo.

Dans le 4ème cas, le shell essaie d'ouvrir le fifo pour la lecture ( < fifo) et l'ouvrir pour l'écriture ( > fifo) dans le cadre du même processus. La coquille les fait un à la fois, de gauche à droite. Il essaie donc de s'ouvrir fifopour la lecture, et bloque pour toujours, attendant que quelque chose s'ouvre fifopour l'écriture. Je pense que vous constaterez que dans ce cas, ncjamais même commencé, et le port n'a jamais été ouvert pour l'écoute.

Mikel
la source
Oh ouais erreur idiote dans # 3, mais à la fin le résultat reste le même. Juste une autre question qui est plus curieuse qu'autre chose, est-ce que l'exec est le seul moyen d'ouvrir le fifo pour r / w en une seule étape? Et existe-t-il un autre moyen de forcer le shell à bifurquer comme dans # 1? Je vous remercie!
foo
nc ... <>fifodevrait être suffisant. gnu.org/software/bash/manual/html_node/Redirections.html
Mikel
1
Le shell se bifurque à chaque fois que vous utilisez un pipeline, un sous-shell ou une substitution de processus.
Mikel
2
Correction, vous en aurez besoin nc ... <>fifo >&0, car <>fifoouvre fifopour la lecture et l'écriture sur fd 0, et nous voulons que la sortie y aille aussi.
Mikel