Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

How do I do a non-blocking accept?

by Anonymous Monk
on Mar 30, 2000 at 19:08 UTC ( #6535=perlquestion: print w/ replies, xml ) Need Help??
Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I'm playing with sockets (I'm on 'use Socket' not 'use IO::Socket' - I want to play with the low-level stuff then I'll look at the high-level version) I'm doing ok except for the infuriating 'does the same as the system call of the same name' which I find thoughout the manual. Problem is a windows system doesn't document unix system call very well! - Back to the point - my accept is working ok - but is a 'blocking' call (i.e: waits until data arrives before returning). I assume there is a non-blocking version of accept which I can use to check if there is data present but will return immediately if none is present. Problem is I don't know how to do this. I'm assuming it's a setsockopt of some kind - or a parameter to accept, but the manual won't tell me...;-(. Help please. Many thanks - cool web site by the way! Richard.

Comment on How do I do a non-blocking accept?
Re: How do I do a non-blocking accept?
by chromatic (Archbishop) on Mar 30, 2000 at 22:01 UTC
    My notes recommend something like this (assuming Connection is your socket descriptor?):
    use Fcntl; fcntl(Connection, F_SETFL, O_NONBLOCK) or die "can't set non blocking: $!";
    I suppose you could also wrap your Socket->accept() in alarm() calls....
Re: How do I do a non-blocking accept?
by btrott (Parson) on Mar 31, 2000 at 01:57 UTC
    Also, you may already know this, but if you use the non-blocking accept, I believe you can check $! for EAGAIN (or EWOULDBLOCK on BSD and perhaps other systems) to check whether there are no connection requests (as opposed to accept just failing for some other reason). Maybe not on your system, though...

    As an aside: I know it's quite annoying to be pointed towards man pages that you don't have on your system... here's a good source of man pages for OpenBSD, and here's some docs (in troff source) for Unix Version 7.

Re: How do I do a non-blocking accept?
by thecap (Initiate) on Apr 07, 2000 at 07:09 UTC
    You should check out perl-chat in Tkil's Perl Examples. It uses the low level calls to select, sysread and syswrite. The diffcult thing about using select is that you can't use <SOCK> and print SOCK with nonblocking io.

    When you move to the higher level IO::* you might find Tkil's port-forward a useful guide.

Re: How do I do a non-blocking accept?
by mattr (Curate) on Sep 01, 2000 at 09:24 UTC
    If you like playing with lowlevel interfaces, you might like to install Cygwin (sources.redhat.com/cygwin) which will give you a unix shell and a basic system with compiler, man pages, etc. Then maybe you could download packages from gnu.org and read their manpages or try them out from the command line. Seems to use Unix sockets with the option of recompiling things to use Windows sockets according to the faq.

    Hope this helps,
    Matt

Re: How do I do a non-blocking accept?
by dl748 (Initiate) on Jun 02, 2001 at 02:53 UTC
    ACCEPT is a blocking function. Under Unix/perl i know you can't set it up as nonblocking.
Re: How do I do a non-blocking accept?
by Anonymous Monk on Nov 07, 2001 at 14:32 UTC

    THIS WORKS!!!!

    (Tested on Win32 with indigo and activestate perl)

    vec($bits1,fileno($server),1)=1;
    while(1) {
     $rc=select($rout1=$bits1,$wout1=$bits1,$eout1=$bits1,0.5); # poll
     print "select($rout1,$wout1,$eout1,0)=$rc\n";
    }
    

    When there's a connection, $rout1 gets set.

Re: How do I do a non-blocking accept?
by Anonymous Monk on Mar 27, 2002 at 04:23 UTC
    fcntl(sockfd,F_SETFL,FNDELAY) can be used to set the file descriptor in to a non blocking mode, any blocking system call on this descriptor including accept will return immediately and set the errno=EWOULDBLOCK regards rakesh soni
Re: How do I do a non-blocking accept?
by davidnicol (Acolyte) on Aug 22, 2004 at 04:48 UTC
    you have to set the listening socket to nonblocking, as documented in the man page for accept. This can be done with fcntl rather than setsockopt. As explained above here at How do I do a non-blocking accept?.
Re: How do I do a non-blocking accept?
by davidnicol (Acolyte) on Aug 23, 2004 at 01:46 UTC
    I was flummoxed by the lack of the nonblocking flags on sockets on microsoft windows, until I realized that inside a nonblocking accept(2) call, accept(2) is just going to have to do something like a select(2).

    So a non-blocking accept IS NEVER REQUIRED because you can either

    • just accept one connection per iteration -- the other ones will still be there on the next iteration or
    • When you have a hot listening socket, accept the first connection AND THEN SELECT AGAIN ON IT AND ONLY IT.

    So instead of

    foreach (@Listeners){ vec($rout,fileno($_),1) or next; # listener is nonblocking, goes until # expected accept failure while (accept(my $NewServer, $_)){ push @Clients, $NewServer
    you just do do
    foreach (@Listeners){ vec($rout,fileno($_),1) or next; # listener is blocking, but we # know this listener is hot if (accept(my $NewServer, $_)){ push @Clients, $NewServer }else{ log "accept: $!" }
    Or, mock up the accept-em-all-NOW method without clumsily making accept fail:
    foreach (@Listeners){ vec($rout,fileno($_),1) or next; # listener is blocking, but we # know this listener is hot acc: accept(my $NewServer, $_) and push @Clients, $NewServer; # select again to see if there's another my $rvec; vec($rvec,fileno($_),1) = 1; select($rvec,undef,undef,0); vec($rvec,fileno($_),1) and goto acc;

    The difference is

    by accepting all connections immediately we will possibly have more connections going, more suddenly. If we have a limit on our number of open connections, we only need to check it once per loop to keep from overrunning it.

    How much can it affect throughput? It's like asking is it better for an office building to have a one-person revolving door that spins fast or a family-size one that spins slow.

Re: How do I do a non-blocking accept?
by Matts (Deacon) on Aug 25, 2004 at 11:06 UTC
    First, you setup your server:
    my $server = IO::Socket::INET->new( %params, Blocking => 0 );
    Then make it non-blocking, for perls that don't obey the Blocking param above:
    IO::Handle::blocking($server, 0);
    Then you add that server to your select vector watching for read events. When a client is waiting to be accept()ed, the select will return your server as ready to read. Just compare the sockets using == to determine if the socket is your server, and if it is, issue accept(). Note that by the time you get to it the client may have changed his mind, and so your accept could return EWOULDBLOCK or EAGAIN, so you have to check for that.
Re: How do I do a non-blocking accept?
by posicat (Initiate) on Oct 11, 2004 at 19:54 UTC
    I spent a few hours and finally found this paramater you can pass to the IO::Socket::INET ... Timeout =>
    my $sock = new IO::Socket::INET ( LocalPort => '1401', Proto => 'tcp', Listen => 1, Reuse => 1, Timeout => .1, );
    After .1 seconds it times out the accept command and continues on through your loop happily. As an added benefit this helps you prevent race conditions.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://6535]
Approved by davido
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others romping around the Monastery: (16)
As of 2014-07-14 17:12 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    When choosing user names for websites, I prefer to use:








    Results (269 votes), past polls