2015-02-14 15 views
7

Sto provando a creare una connessione persistente usando bash. Il terminal 1, tengo un netcat esecuzione come un server:Connessione persistente nello script Bash

$ nc -vlkp 3000 
Listening on [0.0.0.0] (family 0, port 3000) 

su Terminal 2, creo una FIFO e mantenere un gatto:

$ mkfifo fifo 
$ cat > fifo 

su Terminal 3, faccio la FIFO come ingresso a un netcat client:

$ cat fifo | nc -v localhost 3000 
Connection to localhost 3000 port [tcp/*] succeeded! 

su terminal 4, mando quello che voglio:

$ echo command1 > fifo 
$ echo command2 > fifo 
$ echo command3 > fifo 

Tornando al terminal 1, vedo i comandi ricevuti:

$ nc -vlkp 3000 
Listening on [0.0.0.0] (family 0, port 3000) 
Connection from [127.0.0.1] port 3000 [tcp/*] accepted (family 2, sport 41722) 
command1 
command2 
command3 

Quindi, tutto funziona. Ma quando ho messo che in uno script (ho chiamato che fifo.sh), bash non è in grado di scrivere nella FIFO:

su Terminal 1, stesso server di ascolto:

$ nc -vlkp 3000 
Listening on [0.0.0.0] (family 0, port 3000) 

su Terminal 2, I eseguire lo script:

#!/bin/bash 

rm -f fifo 
mkfifo fifo 
cat > fifo & 
pid1=$! 
cat fifo | nc -v localhost 3000 & 
pid2=$! 

echo sending... 
echo comando1 > fifo 
echo comando2 > fifo 
echo comando3 > fifo 

kill -9 $pid1 $pid2 

l'output di terminale 2 è:

$ ./fifo.sh 
Connection to localhost 3000 port [tcp/*] succeeded! 
sending... 

il terminale 1 mi vede solo il connec zione. Nessun comando:

$ nc -vlkp 3000 
Listening on [0.0.0.0] (family 0, port 3000) 
Connection from [127.0.0.1] port 3000 [tcp/*] accepted (family 2, sport 42191) 
Connection closed, listening again. 

Qualche idea sul motivo per cui funziona solo in modo interattivo? O c'è un altro modo per creare una connessione persistente usando solo Bash? Non voglio andare su Expect perché ho uno script Bash più grande che funziona dopo aver inviato il comando 1, e il comando 2 dipende dall'output di command1, ecc.

Grazie!

+1

Ciao e benvenuto su Stack Overflow! Questa è la migliore domanda per principianti che abbia mai visto. – l0b0

risposta

2

Quando un processo viene avviato in background in uno script, l'input standard viene reindirizzato da /dev/null. Questo significa che il primo comando cat leggerà ed emetterà EOF non appena viene eseguito, il che causerà l'uscita di netcat immediatamente dopo l'avvio, quindi l'output più avanti nello script non lo farà mai al fifo, perché non c'è un listener attivo a quel tempo.

In questo caso, quando viene valutato cat > fifo, la shell esegue il fork di un processo figlio, reindirizza lo standard input da /dev/null e tenta di aprire fifo per scrivere. Il bambino rimane in una chiamata di blocco open in questo momento. Si noti che cat non viene eseguito fino al termine della chiamata open.

Successivamente, viene generato il numero cat fifo | nc -v localhost 3000. cat apre fifo per lettura, che consente il blocco open dal primo figlio da completare e il primo cat da eseguire.

Il primo cat eredita descrittori di file del suo genitore, per cui il suo standard input è attaccato al /dev/null e si legge in tal modo ed emette un EOF immediatamente.Il secondo cat legge EOF e lo passa allo standard input di nc, che causa l'uscita di netcat.

Quando i echo istruzioni vengono valutati, i processi identificati da $pid1 e $pid2 sono finiti. Poiché non c'è più un listener su fifo, il primo echo si bloccherà per sempre.


Non ho una correzione pura-shell, ma è possibile utilizzare un programma esterno, come Perl per aprire lo scrittore segnaposto per fifo invece di utilizzare il reindirizzamento shell. A parte, c'è una gara con nc che inizia dopo le dichiarazioni echo (dove lo kill accade prima che netcat abbia la possibilità di elaborare input/send output), quindi qui ho aggiunto un ritardo dopo l'espressione cat | nc. C'è quasi certamente una soluzione migliore là fuori, ma ecco quello che mi si avvicinò con:

#!/bin/bash 

rm -f fifo 
mkfifo fifo 
perl -e 'open(my $fh, ">", "fifo"); sleep 3600 while 1' & 
pid1=$! 
cat fifo | nc -v localhost 3000 & 
pid2=$! 

sleep 2 

echo sending... 
echo comando1 > fifo 
echo comando2 > fifo 
echo comando3 > fifo 

kill -9 $pid1 $pid2 

Spero che questo aiuti, grande domanda!