Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to trap the error when I've successfully created a socket on the client, but the server dies before I send the msg.

Basically, I'm hoping to keep the connection for a long time (multiple msgs), rather than create/destroy a socket for each msg, as this will be very frequent.

I've tried adding 'or die...' to the print, but that didn't work. I've also tried eval as below but no joy.

Whatever I try, the client crashes with 'Broken pipe' msg at the shell level. I need to trap/handle the error from within Perl.

eval { print $socket "Client msg\n"; }; warn "lost server $@\n" if $@;

Replies are listed 'Best First'.
Re: Trapping socket error in client when server goes away
by mifflin (Curate) on Oct 20, 2004 at 01:37 UTC
    Trap sigpipe in your eval...
    eval { local $SIG{PIPE} = sub {die "SIGPIPE" }; print $socket "Client msg\n"; }; warn "lost server $@\n" if $@;
Re: Trapping socket error in client when server goes away
by pg (Canon) on Oct 20, 2004 at 02:46 UTC

    I don't think eval is a good idea, try to do a select before the print, see whether the socket is actually ready for write.

      There is indeed no need of an eval, Unfortunately selecting for writability (or readability for EOF) doesn't solve the real problem, which is SIGPIPE as result of writing to a closed socket. And that close can happen after the select told the socket was writable but before you got to doing the write. The conventional solution in socket programming is to simply ignore SIGPIPE (usually even globally) and use the returncodes of the I/O operations instead.

      $SIG{PIPE} = "IGNORE"; .... print($socket $string) || die "Error writing to socket: $!"
      (or do something else than die of course, or catch the die in some enclosing eval)
        Thx thospel, that seems to do the trick.

        BTW, as this is all on the same machine ie client+server, would UNIX socket be faster than local INET? Just wondered whether the fact there's a disk file for UNIX socket slows it down?

        The proj handles packets from a busy RADIUS server, so speed is of the essence...

Re: Trapping socket error in client when server goes away
by perlcapt (Pilgrim) on Oct 20, 2004 at 15:14 UTC
    For checking the state of a socket, I prefer to the system call version of select RBITS, WBITS, EBITS, TIMEOUT. It requires a little more setup using vectors and such, but the result is finer control, IMHO. -ben (perlcapt)
    # socket is already setup, and client accepted # set up masks for use by select my ($rin,$win,$ein) = ("","",""); my ($rout,$wout, $eout) = ($rin, $win, $ein); vec($rin, fileno($client),1) = 1; vec($win, fileno($client),1) = 1; $ein = $rin | $win; # -- code deleted -- # wait until the client is ready for writing if(select(undef,$wout = $win,undef,$timeout)) { # <$client> or sysread } # -- code deleted -- # or # wait until client is ready for writing to if(select(undef,$wout=$win,undef,$timeout)) { # print client or syswrite }
      Use of select does not solve the original problem, but just replaces it with a race condition. A socket can get closed between select returning writability and you doing the write. In that case he will run into exactly the same problem, the program will exit with a broken pipe message. It will just be more rare since you made the problem window smaller.

      Also, if you go select based, do not use <> (readline) and print (ok, you can if you are very careful). select only guarantees one read or write respectively (and even that one isn't absolutely guaranteed) These buffered operations can use multiple reads and writes.

        So in other words, expect the read/write to fail. That way, if/when it does, the program won't die

        No one has seen what you have seen, and until that happens, we're all going to think that you're nuts. - Jack O'Neil, Stargate SG-1