http://qs321.pair.com?node_id=322586

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

Hi Monks,

I'm writing a daemon that will listen on UNIX socket, accept connections, take a request, crunch a bit on it, and spit out a response.

A problem arises when server closes connection after writing out on socket what it had to say. Somehow the data gets lost and client never receives it.

A kludge is to add sleep(1) just before the close. But, this is not acceptable in "production" application because it severely limits throughput to less than 1 msg/sec.

Is there a way to make IO::Socket::UNIX do a REAL FLUSH on that UNIX socket so client could read the data that's been written to it?

Here is the server's code:

#!/usr/bin/perl -w use IO::Socket::UNIX; use strict; my $sockfile = '/tmp/mysocket'; my $r; unlink($sockfile); my $usock = new IO::Socket::UNIX( Type => SOCK_STREAM, Local => $sockfile, Listen => 1) || die "ERROR: $!\n"; while (1) { if (($r) = $usock->accept) { my $out = do_something($r); $r->printflush($out); # sleep 1; # this makes it work $r->close; } } sub do_something { my ($fh) = @_; my ($l) = <$fh>; return uc($l); }

And here is my sample UNIX socket client:

#!/usr/bin/perl -w use IO::Socket::UNIX; my ($sockfile) = shift || die "$0: Socket address required\n"; my $r; my $usock = new IO::Socket::UNIX (Type => SOCK_STREAM, Peer => $sockfile) || die "ERROR: $!\n"; # read stdin and write to socket while(<>) { print $usock $_; } # shut down writing side (server receives EOF) $usock->shutdown(1); $sock->blocking(1); # this does not help # read socket (blocking) and write to stdout while(<$usock>) { print $_; } # shut down reading side $usock->shutdown(0);

I've tried SO_LINGER stuff (snippet found on google/groups) in server...

my $linger = pack('ii', 1, 120); # BSD struct $usock->sockopt(SO_LINGER, $linger);

But to no avail.

PLEASE HELP!!™ :)

Damir Dzeko -- PGP keyID: 38ED4CFF

Replies are listed 'Best First'.
Re: IO::Socket::UNIX close() discards data when called "too soon"?
by pfaut (Priest) on Jan 20, 2004 at 14:58 UTC

    Your server is only reading one line from the client. If your client sends multiple lines, it's possible that the server has closed the socket before the client finishes sending all of his information. In this case, the attempt to print to the socket is probably getting a SIGPIPE aborting your client before it even gets a chance to read the socket. By adding the sleep() call, you have given the client more time to finish writing all of the extra data to the socket and it can complete successfully.

    Try adding $SIG{PIPE} = sub { print "SIGPIPE\n"; }; to your client code somewhere near the top. If 'SIGPIPE' ever gets printed at the client end, then what I described above is happening.

    90% of every Perl application is already written.
    dragonchild
      It should read all the lines, as the readline brackets are in a list assignment - it only returns the first line though. The program works fine here, perl 5.8.2 on linux 2.4.21

        The server reads from the client with the following line in do_something():

        my ($l) = <$fh>;

        That is not a list assignment. If you want to read all of the data from the client, try adding local $/ = undef; before the above line.

        90% of every Perl application is already written.
        dragonchild