Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical

Using select() on only one socket

by ivanatora (Sexton)
on Sep 04, 2005 at 08:53 UTC ( #489030=perlquestion: print w/replies, xml ) Need Help??

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

I use IO::Socket for making a connection to TCP server. I want that connection to be non-blocking and I try to use IO::Select for that purpose. However, I have only one socket, and I use mainly the can_read() method, so if nothing comes from the socket, the conn will be non-blocking, untill something come. Here is the way I do:
my $sock = ... my $sel = IO::Select->new(); $sel->add($sock); while (1){ if ($sel->can_read(0.5)){ $line = <$socket>; print $line; } else { print "."; } } #end of while 1
In that way I thing that if nothing comes, I should get a row of dots printed. If something comes it should get printed instead of a dot.
Whatever.. nothing happens. Any ideas?

Replies are listed 'Best First'.
Re: Using select() on only one socket
by gargle (Chaplain) on Sep 04, 2005 at 10:26 UTC


    Interestingly enough this code works:

    The server sends the numbers from 0 to 1000 a second at a time. Maximum 5 clients are catered for.

    #!/usr/bin/perl use strict; use warnings; use IO::Socket; my $server = IO::Socket::INET->new(LocalPort => 5000,Listen =>5); while (my $client = $server->accept()) { foreach my $i (0..1000) { sleep (1); print $client $i . "\n"; } close $client; }

    The client looks for a 'working' socket. If nothing found it will print a dot. If found it will get a handle to read the socket.

    #!/usr/bin/perl use strict; use warnings; use IO::Socket; use IO::Select; use IO::Handle; my $server = IO::Socket::INET->new(PeerAddr => "localhost",PeerPort => + 5000, Proto => "tcp"); my $sel = new IO::Select; $sel->add($server); while (1) { my @handles = $sel->can_read(0.10); if (@handles) { foreach my $s (@handles) { my $line = <$s>; print $line; } } else { print "."; } }
    if ( 1 ) { $postman->ring() for (1..2); }

      Problem solved!

      I didn't use the handles returned from can_read(). Actually I thought that I can use the initial $sock filehandle after the select statement... When I use the handle returned from can_read, it works perfectly :)

        I know you already got a solution, but...

        Could the real problem be because your example used $sock when you create the socket and add it to the select, but $socket on the line where you try to read it ? (use strict should catch this though, so perhaps it's just a typo you made while entering the example)

Re: Using select() on only one socket
by dws (Chancellor) on Sep 04, 2005 at 09:20 UTC

    .. nothing happens. Any ideas?

    Unless you've done something interesting with $/ , $line = <$socket>; tries to read a complete line of text from the socket, blocking until one is available. Is there a full line available?

      Yes, a lot of lines come in.

        The Camel has the following to say (much better than I could!):

        A common misconception in socket programming is that \n will be \012 everywhere. In many common Internet protocols, \012 and \015 are specified, and the values of Perl's \n and \r are not reliable since they vary from system to system:

        print SOCKET "Hi there, client!\015\012"; # right print SOCKET "Hi there, client!\r\n"; # wrong

        However, using \015\012 (or \cM\cJ, or \x0D\x0A, or even v13.10) can be tedious and unsightly, as well as confusing to those maintaining the code. The Socket module supplies some Right Things for those who want them:

        use Socket qw(:DEFAULT :crlf); print SOCKET "Hi there, client!$CRLF" # right

        When reading from a socket, remember that the default input record separator $/ is \n, which means you have to do some extra work if you're not sure what you'll be seeing across the socket. Robust socket code should recognize either \012 or \015\012 as end of line:

        use Socket qw(:DEFAULT :crlf); local ($/) = LF; # not needed if $/ is already \012 while (<SOCKET>) { s/$CR?$LF/\n/; # replace LF or CRLF with logical newline }

        Perl is Huffman encoded by design.
Re: Using select() on only one socket
by ambrus (Abbot) on Sep 04, 2005 at 10:24 UTC

    Sorry for stating the obvious if you have done all of the below.

    First, you should just try to change the loop to a simple

    while (1){ $line = <$socket>; print $line; }
    for testing.

    If that prints the lines, then I don't know what the problem is.

    If that doesn't print anything either, then the problem is probably not in the select loop. It could be that you don't receive complete lines, as others have suggested; or that you don't receive any data on the socket (maybe the other side is waiting for you to send something first); or that you are trying to read from a listening socket (as opposed to an accepted or a connected socket).

    Also you have checked that the loop actually starts, the program doesn't hang somewhere before that, haven't you?

      I tried that, and it prints the incoming line. Also the select loops starts. I've change the following:
      print "bob\n"; my $sel = IO::Select->new(); $sel->add($sock); while (1){ print "!"; if ($b = $sel->can_read(0.5)){ $line = <$socket>; print $line; } else { print "."; } } #end of while 1
      I see 'bob' printed, so the program is running there. After that I see infinite '!'s, so the loop starts. But nothing more. No dots, no lines.
Re: Using select() on only one socket
by Anonymous Monk on Sep 04, 2005 at 15:20 UTC
    I see you solved your problem, but thought I'd mention this anyway since so few people realize it.

    When select() says a file descriptor is readable it really means that it *might* be readable. You still have to use nonblocking I/O to be sure you won't block.

      This is not correct: the whole point of can_read is that it tells you that there's data waiting to be read in the filehandles it returns. Probably you're referring to some particular environment or operating system I'm not considering at the moment?

      perl -ple'$_=reverse' <<<ti.xittelop@oivalf

      Don't fool yourself.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://489030]
Approved by Roger
Front-paged by halley
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others rifling through the Monastery: (8)
As of 2020-11-25 20:27 GMT
Find Nodes?
    Voting Booth?

    No recent polls found