Bloehdian has asked for the wisdom of the Perl Monks concerning the following question:
Hello Monks,
this time I cannot post the actual code I am using due to an NDA (whereby: the SERVER script below is exactly what I use in production, only the CLIENT stuff must not be published.
My question is more of general nature anyway. It can be illustrated with the following code examples (which actually do not show the problem).
I have a client (script) connecting to a TCP socket on which the server (script) is listening and to which the client constantly sends short text messages. The messages are generated within a child process generated with fork.
When both the client and server are running I simulate network connectivity problems by pressing CTRL-C to interrupt the server. The server stops running and, obviously from output, parent AND child process are still running (TWO related process in the process list).
With my actual production script, which contains much more code in the child section, normally the child deceases and only the parent keeps on running (only ONE process in the process list). $! says "Broken pipe".
Is there a safe method to prevent this, i.e., to keep the child running as well?
I tried, as in the examples, catch the PIPE signal by IGNOREing it and other things, but nothing turned out to be working.
Any hint is appreciated.
CLIENT:
SERVER:#/usr/bin/perl use warnings; use IO::Socket::INET; use Scalar::Util; $port = '7777'; if ( defined $ARGV[0] ) { $port = $ARGV[0] } $SIG{ 'TERM' } = $SIG{ 'INT' } = sub { print( "died() or caught TERM/INT\n" ); exit(); }; $SIG { 'PIPE' } = 'IGNORE'; pipe( $reader, $writer ); $writer->autoflush(1); if ( ! defined ( $pid = fork() ) ) { die( "Cannot fork!: $!" ) } elsif ( $pid == 0 ) { # Child # $line = ''; # A line of data to be read # Connect to socket # $connected = 0; while ( 1 ) { eval { undef $socket; $socket = IO::Socket::INET->new ( PeerHost => '127.0.0.1', PeerPort => $port, Proto => 'tcp' ); }; if ( $@ ) { print "$@\n" } if ( defined $socket ) { print( "Connected!\n" ); $connected = 1; } else { print( "Could not connect!\n" ); $connected = 0; die(); } close $writer; while ( $connected ) { defined ( $line_2 = <$reader> ) or last; print( "CHILD: Received line $line_2\n" ); eval { if ( defined $socket->send( $line_2 ) ) { print ( "CHILD: \$socket->send() successful: $line_2 +\n") ; #shutdown( $socket, 1 ); $response = ""; $socket->recv($response, 1024); print "CHILD: received response: $response\n"; } else { print( "Not connected!\n" ); $connected = 0; } }; if ( $@ ) { print( "CHILD: error when trying to send(): $@ +" ) } } close $reader; } } else { # Parent # close $reader; for ( $i=1; $i<=5; $i++ ) { $line = "-- " . $i . " --"; print( "PARENT: Going to transfer line $line\n" ); eval { if ( print $writer "$line\n") { print ( "PARENT: Successfully pushed to child!\n" ); } }; if ( $@ ) { print( "$@\n" ) } sleep 1; } close $writer; print "PARENT: closed writer, waiting for child to exit\n"; 1 while wait > 0; }
use IO::Socket::INET; my $port = '7777'; if ( defined $ARGV[0] ) { $port = $ARGV[0] } # auto-flush on socket $| = 1; $SIG{ 'TERM' } = $SIG{ 'INT' } = sub { $socket->close(); }; $SIG{ 'PIPE' } = 'IGNORE'; my $client_socket; # creating a listening socket my $socket = new IO::Socket::INET ( LocalHost => '0.0.0.0', LocalPort => $port, Proto => 'tcp', Listen => 5, Reuse => 1 ); die "cannot create socket $!\n" unless $socket; print "server waiting for client connection on port $port\n"; # waiting for a new client connection $client_socket = $socket->accept(); while(1) { # get information about a newly connected client my $client_address = $client_socket->peerhost(); my $client_port = $client_socket->peerport(); print "connection from $client_address:$client_port\n"; # read up to 1024 characters from the connected client my $data = ""; $client_socket->recv($data, 1024); print "received data: $data\n"; # write response data to the connected client $data = "ok"; $client_socket->send($data); # notify client that response has been sent #shutdown($client_socket, 1); }
CLIENT output:
SERVER output:PARENT: Going to transfer line -- 1 -- PARENT: Successfully pushed to child! Connected! CHILD: Received line -- 1 -- CHILD: $socket->send() successful: -- 1 -- CHILD: received response: ok PARENT: Going to transfer line -- 2 -- PARENT: Successfully pushed to child! CHILD: Received line -- 2 -- CHILD: $socket->send() successful: -- 2 -- CHILD: received response: ok PARENT: Going to transfer line -- 3 -- PARENT: Successfully pushed to child! CHILD: Received line -- 3 -- CHILD: $socket->send() successful: -- 3 -- CHILD: received response: PARENT: Going to transfer line -- 4 -- PARENT: Successfully pushed to child! CHILD: Received line -- 4 -- CHILD: error when trying to send(): send: Cannot determine peer addres +s at test_4.pl line 70. PARENT: Going to transfer line -- 5 -- PARENT: Successfully pushed to child! CHILD: Received line -- 5 -- CHILD: error when trying to send(): send: Cannot determine peer addres +s at test_4.pl line 70. PARENT: closed writer, waiting for child to exit Could not connect! Died at test_4.pl line 58.
server waiting for client connection on port 7775 connection from 127.0.0.1:37480 received data: -- 1 -- connection from 127.0.0.1:37480 received data: -- 2 -- connection from 127.0.0.1:37480 ^CCan't call method "close" on an undefined value at sim.pl line 8.
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: IO:Socket::INET: Strategies against death of child processes on broken pipe
by Corion (Patriarch) on Oct 13, 2016 at 08:23 UTC | |
by Bloehdian (Beadle) on Oct 13, 2016 at 10:43 UTC | |
by Corion (Patriarch) on Oct 13, 2016 at 11:22 UTC | |
|
Re: IO:Socket::INET: Strategies against death of child processes on broken pipe
by tybalt89 (Monsignor) on Oct 13, 2016 at 15:00 UTC |