2013-01-16 4 views
9

voglio avere un demone Perl ascoltare e accettare una connessione in entrata da un client, e quindi forchetta & exec un altro programma Perl per continuare il conversazione con il cliente.Perl - superamento di un socket aperto attraverso fork/exec

È possibile eseguire questa operazione con la semplice foratura, in cui il codice daemon contiene anche il codice figlio. Ma non vedo come il socket aperto possa essere "passato" attraverso un exec() in un altro programma Perl.

In qualche modo ho avuto l'impressione che fosse facile in Unix (che è il mio ambiente) e quindi anche in Perl. Può davvero essere fatto?

risposta

14

questo può essere fatto in circa tre fasi:

  1. Cancella il close-on-exec bandiera sul descrittore di file.
  2. Comunicare al programma exec quale programma di descrizione del file utilizzare.
  3. Ripristina il descrittore di file in un handle.

1. Perl (per impostazione predefinita) imposta il flag close-on-exec su descrittori di file si apre. Ciò significa che i descrittori di file non verranno conservati attraverso uno exec. È necessario cancellare questo flag prima:

use Fcntl; 

my $flags = fcntl $fh, F_GETFD, 0 or die "fcntl F_GETFD: $!"; 
fcntl $fh, F_SETFD, $flags & ~FD_CLOEXEC or die "fcntl F_SETFD: $!"; 

2. Ora che il descrittore di file rimarrà aperto tutta exec, è necessario indicare al programma che DESCRIPTOR è:

my $fd = fileno $fh; 
exec 'that_program', $fd; # pass it on the command line 
# (you could also pass it via %ENV or whatever) 

3 . Recuperare il filehandle dall'altra parte:

my $fd = $ARGV[0]; # or however you passed it 
open my $fh, '+<&=', $fd; # fdopen 
$fh->autoflush(1); # because "normal" sockets have that enabled by default 

Ora avete un a maniglia di livello 1 in $fh di nuovo.

Addendum: Come Ikegami menzionato in un commento, si può anche fare che la presa sta usando uno dei tre descrittori di file "standard" (0 (standard input), 1 (stdout), 2 (stderr)), che sono 1. lasciati aperti di default su execs, 2. hanno numeri conosciuti quindi non c'è bisogno di passare nulla, e 3. perl creerà automaticamente maniglie corrispondenti per loro.

open STDIN, '+<&', $fh; # now STDIN refers to the socket 
exec 'that_program'; 

Ora that_program può semplicemente utilizzare STDIN. Funziona anche per l'output; non esiste alcuna restrizione inerente ai descrittori di file 0, 1, 2 che siano solo per input o output. È solo una convenzione che segue tutti i programmi Unix.

+0

Sto per provare la procedura, ma ho una domanda sull'utilizzo di STDIN: può essere associato a una connessione bidirezionale come un socket? Tendo a pensare a fds 0-2 come semi-magico (specializzato in qualche modo per l'I/O del terminale). Sono davvero speciali se non nei modi che hai menzionato nel tuo addendum? – Chap

+0

Il problema che sto riscontrando con la soluzione riguarda l'apertura dell'FD sia per l'input che per l'output. 'apri my $ fh, '<& =', $ fd;' lo apre per l'input.Ho provato a seguirlo con 'open $ fh, '> & =', $ fd;' ma ottiene l'errore: Bad file descriptor. (L'apertura precedente per l'input funziona.) Non riesco a trovare alcuna informazione su come aprire sia per l'input che per l'output. – Chap

+1

Un altro followup: l'open (per i/o bidirezionale) avrebbe dovuto essere 'open $ fh, '+> & =', $ fd;'. Inoltre, avevo bisogno di pubblicare '$ fh-> autoflush (1)'. – Chap