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

OK, so I want to build myself a program that does things while listening for messages on a socket. NB, both are important. It has to listen, and it has to do stuff.

So I looked into IO::Select and non-blocking IO, and wrote (something like) this:

while (1) { print "yo\n"; while ( my @handles = $self->{daemon}->can_read(1) ) { foreach ( @handles ) { if ($_ == $self->{listener}) { my $new_sock = $self->{listener}->accept or die "accept: $!"; $self->{daemon}->add( $new_sock); } else { my @rawmsg = $_->getlines; print @rawmsg; #$_->close; } } } }

Where,as you may guess $self->{daemon} is an IO::Select and $self->{listener} is a listening IO::Socket object. So I am trying to listen for calls, while periodically printing "yo". One day, "yo" will be replaced by interesting stuff.

My problem is this: if I don't do close on new sockets, the socket blocks, and I get:

yo yo yo yo message from client

and then nothing. But if I include the close() call, then the socket stops blocking, but can_read doesn't wait at all next time. I get:

yo yo yo yo message from client yo yo yo

with an infinite row of yos, and no more client messages.

How do I get can_read to be good second time round? More generally, is this a good way to go about things? I thought about forking a message receiver which would then pass messages via a pipe... but then I thought that I'd need to block while waiting for the pipe... seems like I need a language with better multithreading but maybe someone can tell me better...

best

dave hj~

Replies are listed 'Best First'.
Re: non-blocking select with IO::Select
by c-era (Curate) on Jul 03, 2001 at 18:19 UTC
    Here are a couple of sugestions. You need to remove the socket from the io::select before you close it. You also need to check the length of what you get from the socket to see if it was closed. Try this code and let me know if it works (I had to guess at some parts).
    while (1) { print "yo\n"; while ( my @handles = $self->{daemon}->can_read(1) ) { foreach ( @handles ) { if ($_ == $self->{listener}) { my $new_sock = $self->{listener}->accept or die "accept: $!"; $self->{daemon}->add( $new_sock); } else { my @rawmsg = $_->getlines; if ($rowmsg[0]){ # Or what ever the index of the message is print @rawmsg; } else { $self->{daemon}->remove($_); $_->close; } } } }
    Here is some code that I wrote that works with non-blocking and multiple clients.
    use IO::Socket; use IO::Select; my $sock = new IO::Socket::INET (LocalHost => '127.0.0.1', LocalPort => 1200, Listen => 5, Proto => 'tcp', Reuse => 1, ) or die $!; my $handles = new IO::Select(); $handles->add($sock); while (1){ print "yo"; my ($s_handles) = IO::Select->select($handles, undef, undef, 1); for my $hndl (@$s_handles){ if ($hndl == $sock){ $handles->add($hndl->accept()); } else { if (my $line = <$hndl>){ print $line; } else { $handles->remove($hndl); close ($hndl); } } } }

      The second example is exactly what I was after -- but how can I get information from the sockets? Both 'hndl' and the value returned from '$hndl->accept()' are IO::Socket::INET objects, but neither provide any return values from that object, such as peeraddr or peerhost. How do I know which client it is, in that amorphous group of clients? :-}

      ta, N
(tye)Re: non-blocking select with IO::Select
by tye (Sage) on Jul 03, 2001 at 18:42 UTC

    "getlines" reads until it finds $/. The messages on your socket may not all end in $/. So there could be more data available for reading from your socket (hence select says you can read from it) but that data may not contain $/ (so "getlines" hangs waiting for $/ to show up).

    You probably want to use read or sysread instead of "getlines".

            - tye (but my friends call me "Tye")
Re: non-blocking select with IO::Select
by pope (Friar) on Jul 03, 2001 at 18:23 UTC
    Well, if the socket blocks, then make it nonblocking! :-)
    Copied and pasted from Perl Cookbook:
    sub nonblock { my $socket = shift; my $flags; $flags = fcntl($socket, F_GETFL, 0) or die "Can't get flags for socket: $!\n"; fcntl($socket, F_SETFL, $flags | O_NONBLOCK) or die "Can't make socket nonblocking: $!\n"; }
Re: non-blocking select with IO::Select
by dash2 (Hermit) on Jul 03, 2001 at 20:13 UTC
    c-era: I kiss you. The remove() sorted it.

    tye and c-era: How does getlines() work in a socket context? It will split the data on $/, right, like angle brackets... but how does it know when the socket has "finished"? Or doesn't it?

    anybody: still wondering if I am doing the right thing. What will happen if I replace print "yo"; with something longer and more complicated? Will the IO::Socket listener start rejecting people? Or does it queue them up?

    xxx

    dave hj~

      The getlines() work just like it does on files. When the socket has finished an EOF is sent, just like when working with files.

      IO::Socket has a parameter called Listen. This controls the number of connections that can be waiting for an accept. I.E. if you have Listen => 10, if 11 people connect to your server while it is busy, 10 people will be waiting, and 1 person will get a server busy error.

      I hope this answers your questions.