f



Need help with a simple UNIX sockets server based on IO::Socket::UNIX

Hi. I've tried to create a simple client + server that communicate
through a unix socket.

As with all socket servers, it has a loop where it waits for
connections:

while ($client = $sock->accept()) {
  # handle client here
}

The problem is that $sock->accept() is returning undef on each
alternate client connection with error "No child processes".

I made this temporary workaround that does work but of course I must be
screwing up somewhere else:

while ($client = $sock->accept() || $client = $sock->accept()) {
  # handle client here
}

I hope someone can help or provide an example. I've included the client
+ server code below for those who are interrested in taking a peek.

Thanks,
Craig Manley

############ client ############
#!/usr/bin/perl -w
use strict;
use IO::Socket;

my $sockname = 'mysocket';

my $client = IO::Socket::UNIX->new('Peer' => $sockname,
                                   'Type' => SOCK_STREAM,
                                   'Timeout' => 50) or die "$0: error
connecting to '$sockname': $ [at] \n";
my $pid = fork();
unless(defined($pid)) {
  die("Fork this! I cannot forking fork!\n");
}
if ($pid) {
  write_sock();
  waitpid($pid, 0);
}
else {
  read_sock();
}

sub write_sock {
  for (1..10) {
    print $client "testline number $_\n"; # print to socket
  }
  print $client "\n"; # empty line causes server to terminate
connection
  print "Done writing.\n"; # (goes to stdout, not socket)
}

sub read_sock {
  while (my $line = <$client>) {
    print $line; # report to stdout
    # simulate someone reading slooowly (50ms/line):
    select(undef, undef, undef, 0.05);
  }
}




########### server ############
#!/usr/bin/perl -w
use strict;
use IO::Socket;
use POSIX ":sys_wait_h"; # (for WNOHANG)
use Data::Dumper qw(Dumper);

# example using unix domain socks
# once the file is created as a socket, any client can
# interact with it

my $sockname = 'mysocket';


service_clients( get_sock() ); # wait for incoming requests


sub get_sock {
  unlink $sockname;
  my $sock = IO::Socket::UNIX->new('Local'  => $sockname,
                                   'Type'   => SOCK_STREAM,
                                   'Listen' => SOMAXCONN) || die "$0:
error starting daemon on '$sockname': $ [at] \n";
  # you might want to change permissions and ownership, e.g.:
  #chmod 0600, $sockname;
  #chown scalar getpwnam('nobody'), 0, $sockname;
  return $sock;
}

sub service_clients {
  my $sock = shift;
  $SIG{CHLD} = \&reaper;
  my $client;
  while ($client = $sock->accept()) { # Why the hell does it return
undef on the next iteration?
  # while ($client = $sock->accept() || $client = $sock->accept()) { #
This strangely enough does work.

    # fork yet another process to prevent buffer deadlock. one proc
writes to
    # the sock, the other reads the deamons response
    my $pid = fork();
    unless(defined($pid)) {
      die("Fork this! I cannot forking fork!\n");
    }
    if ($pid) { # parent
      print "$pid $$: I'm the parent and am going to wait for another
client.\n";
      close($client); # no use to parent
      next; # be ready for another client
    }
    print "$pid $$: I'm the child and I'm going to service the
client.\n";
    # child
    close($sock); # no use to child
    process_requests($client);
    print "$pid $$: I'm the child and I'm going to exit.\n";
    exit; # terminate child
  }
  print "Damnit! I'm the server and I finished unexpectedly: $!\n";
}

sub process_requests {
  my $client = shift;
  $0 = "unixsockd: handling requests...";
  # read from client until empty line which causes it to close
connection
  while ( my $line = <$client> ) { # read line from socket
    if ($line =~ /^\s$/) {
      last; # exit on empty line
    }
    chomp($line);
    # put some more useful code here to read each line or whatever...
    printf $client "%s: %s, handled by PID %d\n",
    scalar localtime(time), $line, $$;
    # return something to client
  }
}

sub reaper {
  while (waitpid(-1,WNOHANG) > 0) {}
  $SIG{CHLD} = \&reaper;
}

0
4/14/2005 9:02:55 AM
comp.lang.perl.modules 4194 articles. 0 followers. jerrykrinock (6) is leader. Post Follow

3 Replies
1101 Views

Similar Articles

[PageSpeed] 37

Oops sorry, the working workaround (not solution) is this:
while (($client = $sock->accept()) || ($client = $sock->accept())) {
   ....
}

0
4/14/2005 9:22:59 AM
"Craig Manley" <glideraerobatics@hotmail.com> wrote in message
news:1113469375.529616.222890@o13g2000cwo.googlegroups.com...
> Hi. I've tried to create a simple client + server that communicate
> through a unix socket.
>

What you have provided doesn't look all that simple to me. At its simplest a
server script (which listens eternally, but can accept only one connection
at a time) could look like this:

-------------------------------------------
use strict;
use IO::Socket;

my ($client, $data_read);

# Server listens at port 2009, for example.
my $server = IO::Socket::INET->new(LocalPort => 2009,
                                   Type      => SOCK_STREAM,
                                   Reuse     => 1,
                                   Listen    => 1 )
 or die "Couldn't be a tcp server on port 2009: $!\n";

while(1) {
print "Server waiting\n";
$client = $server->accept();

$data_read = <$client>;  # Expects a single line

# Do something with the message received from client -
# in this case echo the message back.
print $client $data_read;

close($client);
}
__END__
----------------------------------

and an (also eternal) client script could look like this:

------------------------------------
use strict;
use warnings;
use IO::Socket;

my $remote;
my $port = 2009; #  port at which server listens
my $host = '192.168.0.2'; # server's address

while(1) {

$remote = IO::Socket::INET->new( Proto    => "tcp",
                                 PeerAddr => $host,
                                 Type     => SOCK_STREAM,
                                 PeerPort => $port);

 unless ($remote) {
 die "cannot connect to http daemon on $host\n$!\n";
 }

# This particular script sits here, waiting for input ....
my $data_to_send = <STDIN>;

print $remote "$data_to_send\n"
    or die "Unable to send: $!\n";

# Cater for a multiline reply from the server
my $data_received = '';
while(<$remote>) {$data_received .= $_}

# Do something with the reply -
# in his case simply print out the reply
print $data_received, "\n";

close($remote);
 }
__END__
---------------------------------------------

That's taken from actual scripts that I use on linux, but they have been
modified - which means that I could have rendered them unusable (through
some stupid error).

You'll note that there's no use of IO::Socket::UNIX. Do you need to use that
module ? If so, and you strike difficulty modfiying the above script(s),
then let us know.
There's also no forking. Do you need to fork ? Even if you do, you'll
probably find it useful to get your script working under a scenario where
forking is not required, and then develop it to incorporate forking.

Hth.

Cheers,
Rob


0
sisyphus12 (343)
4/17/2005 11:52:34 AM
"Craig Manley" <glideraerobatics@hotmail.com> wrote:
> Hi. I've tried to create a simple client + server that communicate
> through a unix socket.
>
> As with all socket servers, it has a loop where it waits for
> connections:
>
> while ($client = $sock->accept()) {
>   # handle client here
> }
>
> The problem is that $sock->accept() is returning undef on each
> alternate client connection with error "No child processes".

This is just a wild guess, but I think that what is happening is that
your $sock->accept call is being interupted by the SIGCHLD, and is not
getting automatically restarted once the sig handler finishes.

>
> I made this temporary workaround that does work but of course I must be
> screwing up somewhere else:
>
> while ($client = $sock->accept() || $client = $sock->accept()) {
>   # handle client here
> }

Since it appears that you want the loop to be infinite, why not just make
it explicitly infinite?

while (1) {
  my $client=$sock->accept();
  unless (defined $client) {
    next if $! eq 'Whatever that error was';
    die "Unexpected error $!";
  }
  #.....
}


> I hope someone can help or provide an example. I've included the client
> + server code below for those who are interrested in taking a peek.

Looking through some old code I have, I see that I don't use a sig handler
at all.  I just put the "while (waitpid(-1,WNOHANG) > 0) {}" directly into
"accept" loop, as the first command after the accept.  I don't recall
exactly why I did that, but it may have been due to a problem like what you
see.  In this method, old forked servers stick around as zombies slightly
longer (until the next client connects), but I don't think that that is a
big deal.

>
> Thanks,
> Craig Manley

Xho

-- 
-------------------- http://NewsReader.Com/ --------------------
Usenet Newsgroup Service                        $9.95/Month 30GB
0
xhoster (343)
4/18/2005 6:24:47 PM
Reply: