Click here to get back home

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

 HomeNewsGroups | Search | About
 comp.lang.perl.modules    Post an article   get this group's latest topics as an RSS feed add this group's latest topics to your My MSN content add this group's latest topics to your My Yahoo content
Subject Author Date
Need help with a simple UNIX sockets server based on IO::Socket::UNIX Craig Manley 04-14-2005
Posted by Craig Manley on April 14, 2005, 3:02 am
Please log in for more thread options


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 = &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 %dn",
scalar localtime(time), $line, $$;
# return something to client
}
}

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



Posted by Craig Manley on April 14, 2005, 3:22 am
Please log in for more thread options


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



Posted by Sisyphus on April 17, 2005, 10:52 pm
Please log in for more thread options



> 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 waitingn";
$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 $hostn$!n";
}

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

print $remote "$data_to_sendn"
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




Posted by xhoster on April 18, 2005, 7:24 pm
Please log in for more thread options


> 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


Similar ThreadsPosted
DBD:Excel on unix machine March 9, 2006, 11:18 am
OLE Automation using Perl on a Unix box? April 18, 2006, 7:27 pm
Passing a DBI connection between [Unix] processes January 7, 2005, 1:01 pm
Windows Registry manipulation using Unix April 29, 2005, 11:46 am
uncompressing unix Z files on Win32 November 16, 2005, 8:29 pm
unix perl module install errors November 11, 2004, 3:36 pm
Namespace for Unix File Permission checker August 6, 2005, 9:17 pm
Required Perl Developer w/ UNIX. SQL and Shell Scripting. March 24, 2006, 6:41 pm
creating perl binary using PAR module , execution error under unix March 15, 2008, 7:06 am
Help with Net::SFTP when sftp on unix works. September 21, 2004, 11:14 am

Our other projects:

Art Dolls, Fairies and Mermaids - Sunnyfaces.net

Roy's Linux, Programming and Search Engines messages

1-Script XML SitemapXML Sitemap