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:

#/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; }
SERVER:
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:

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 output:
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.

In reply to IO:Socket::INET: Strategies against death of child processes on broken pipe by Bloehdian

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.