in reply to Re^2: How to Multiplex a Client using IO::Select
in thread How to Multiplex a Client using IO::Select

One example is, STDIN won't work in Windows with select

So don't insist that everything is selectable. Use select on the sockets which is portable, and use a thread for STDIN. There is only 1 STDIN, so the cost is minimal.

Your main dispatch loop then becomes something like:

my $Qstdin = new Thread::Queue; async { $Qstdin->enqueue( $_ ) while defined( $_ = <STDIN> ); }->detach; ... while( 1 ) { if( my @readers = $selector->can_read( 0.1 ) ) { ## See what they have to say } elsif( my @writers = $selector->can_write( 0.1 ) { ## Tell'em what they need to know } elsif( my @exceptors = $selector->has_exception( 0.1 ) { ## Deal with their tantrums } else { while( $Qstdin->pending ) { my $kbinput = $Qstdin->dequeue; ## do whatever } } }

That should be portable to any OS supporting threads:


Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
"Too many [] have been sedated by an oppressive environment of political correctness and risk aversion."

Replies are listed 'Best First'.
Re^4: How to Multiplex a Client using IO::Select
by ikegami (Patriarch) on Oct 13, 2008 at 06:18 UTC

    The second and third timeout should be zero. Better yet, you can combine the three system calls into one:

    while( 1 ) { if ( my ($readers, $writers, $exceptors) = IO::Select::select($selector, $selector, $selector, 0.1) ) { for( @$readers ) { ## See what they have to say } for( @$writers ) { ## Tell'em what they need to know } for( @$exceptors ) { ## Deal with their tantrums } } if( $Qstdin->pending ) { my $kbinput = $Qstdin->dequeue; ## do whatever } }

    Another possible improvement would be to ditch Thread::Queue in favour of a Win32::Socketpair "pipe".

      Another possible improvement would be to ditch Thread::Queue in favour of a Win32::Socketpair "pipe".

      I'd be very reluctant to give up what I know works in favour of something, that despite my recognising it's promise, I've yet to get to grips with. Have you tried Win32::Socketpair yet?

      From my view it just adds complications. You still need a thread to handle STDIN, but now you have the problem of passing socket handles around? How would you construct the above snippet?


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.

        How would you construct the above snippet?

        my ($r, $w) = winsocketpair(); $w->autoflush(1); async { print $w $_ while defined( $_ = <STDIN> ); }->detach; while( 1 ) { if ( my ($readers, $writers, $exceptors) = IO::Select::select($selector, $selector, $selector) ) { for( @$readers ) { ## See what they have to say } for( @$writers ) { ## Tell'em what they need to know } for( @$exceptors ) { ## Deal with their tantrums } } }

        Have you tried Win32::Socketpair yet?

        Turns out it crashes :(

        Update: Removing the calls to ioctl removes the crash and makes the module work. I don't know at what cost, though.

        Win32::Socketpair will only work in windows. i need platform independent one. Thread is ok. I tried below code i faced pblm in windows. The Thread is not detaching for context switch. it rotate in while loop. Correct the below code if i am wrong. Server ======
        use strict; use IO::Socket; use IO::Select; use Sys::Hostname; use constant BUFSIZE => 1024; my $host = hostname; my $port = shift || '10280'; my $socket = new IO::Socket( Domain => PF_INET, Proto => getprotobyname('tcp'), LocalAddr => $host, LocalPort => $port, Listen => 1,#SOMAXCONN, #ReuseAddr => SO_REUSEADDR, ) or die $@; my $buffer; print "Waiting to do service...\n"; while (my $client =$socket->accept) { print "Client: ",$client->peerhost," Connected..\n"; syswrite($client,"Reached Server\n",BUFSIZE); if(sysread($client,$buffer,BUFSIZE)>0) { print "$buffer\n"; } else { print "Client Disconnected..\n"; print "Waiting to do service...\n"; } }
        Client ======
        use strict; use IO::Socket; use IO::Select; use Thread::Queue; use constant BUFSIZE => 1024; my $host = shift or die "Usage: client.pl host [port]\n"; my $port = shift || '10280'; my $socket = new IO::Socket(Domain => PF_INET, PeerAddr => $host, PeerPort => $port, Proto => getprotobyname('tcp'), Timeout => 60,) or die $@; my $readers = IO::Select->new() or die "Can't create IO::Select read o +bject"; #$readers->add(\*STDIN); $readers->add($socket); my $Qstdin = new Thread::Queue; async { $Qstdin->enqueue( $_ ) while defined( $_ = <STDIN> ); }->detach; my $buffer; while (1) { my @readers = $readers->can_read(0.1); foreach my $readservice (@readers) { print "Inside can_read\n"; if(sysread($readservice,$buffer,BUFSIZE)>0) { print "$buffer"; } else { while( $Qstdin->pending ) { my $kbinput = $Qstdin->dequeue; syswrite($readservice,$kbinput."\n",BUFSIZE); } } } }
Re^4: How to Multiplex a Client using IO::Select
by muthuma (Novice) on Oct 13, 2008 at 07:01 UTC
    my $Qstdin = new Thread::Queue; async { $Qstdin->enqueue( $_ ) while defined( $_ = <STDIN> ); }->detach; In this code while waits for input. when does the thread context switch to while(1) loop??. It is looping in while defined ($_ = <STDIN>)

      The following code runs the thread asynchronously and detached:

      async { ... }->detach();

      This starts a separate thread that will read from STDIN and stuff the input into the queue.

Re^4: How to Multiplex a Client using IO::Select
by Anonymous Monk on Oct 13, 2008 at 05:53 UTC
    Ya it is very good idea. I will try with it. Above code snippet is in while 1 loop how does the can_read or selection would know the service has disconnected.. Whether has_exception will take care of it??(will try it). Command on that.

      On disconnect, can_read is triggered. Attempting to read will return 0.

      Update: Alternatively, eof should return true.