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

I have a problem. I'm trying to make a simple server where several clients can connect & send me stuff, and it should send everything received by the clients to STDOUT. The problem is that accept() is blocking the I/O, even though I made socket FH non-blocking. How can I either make accept() non-blocking or use a different function to accomplish the same thing without blocking? Here's the code:
#!/usr/bin/perl my @sock; my $numsocks = 0; my @message; print "Waiting for client to connect...\n"; use Socket; socket(FH, PF_INET, SOCK_STREAM, getprotobyname('tcp')) || die $!; setsockopt(FH, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)); my $sin = sockaddr_in(20000, INADDR_ANY); bind(FH, $sin) || die $!; listen(FH, SOMAXCONN); my $read = ''; vec($read, fileno(FH), 1) = 1; select(FH); $| = 1; select(STDOUT); while (1) { #this is where it blocks if ($cn = accept($sock[$numsocks], FH)) { my($port,$iaddr) = sockaddr_in($cn); my $name = gethostbyaddr($iaddr,AF_INET); print "Connection from $name (", inet_ntoa($iaddr), ") on +port $port\n"; vec($read, fileno($sock[$numsocks]), 1) = 1; $numsocks++; select($sock[$numsocks-1]); $| = 1; select(STDOUT); $| = 1; } #uh.. i probably messed up somewhere below.. please excuse its slo +ppiness : ) $read = ''; for($i=0; $i<$numsocks; $i++) { vec($read, fileno($sock[$i]), 1) = 1; } select($readx=$read,undef,undef,undef); for($i=0; $i<$numsocks; $i++) { print "Checking socket $i...\n"; if (vec($readx, fileno($sock[$i]), 1)) { sysread $sock[$i], $a, 10; print "$a"; #my @lines = split(/\n/, $a); #if (@lines > 0) { # $lines[0] = $message[$i] . $lines[0]; # $message[$i] = ""; #} #$message[$i] .= pop(@lines); #foreach $ii (@lines) { # print "$lines[$ii]\n"; #} print "Read socket $i..\n"; } } } exit;

Edit 2001-03-16 by tye to change title (was "Zip")

Replies are listed 'Best First'.
Re: accept() on non-blocking socket still hangs
by tye (Sage) on Mar 17, 2001 at 03:15 UTC

    if ($cn = accept($sock[$numsocks], FH)) {

    Well, @sock is empty here so you are passing undef to accept. In my testing that dies under Unix and blocks silently under Win32 (well, I'm also using different versions of Perl between the two tests, but I just can't imagine this being a Perl or Unix bug so I'm going to blame Win32 even though I have almost no evidence).

    Even if @sock had something in it, array indices start at 0 in Perl (not 1) so $sock[$numsocks] is never going to be anything but undef if you keep $numsocks equal to 0+@sock.

            - tye (but my friends call me "Tye")
Re: accept() on non-blocking socket still hangs
by Anonymous Monk on Mar 17, 2001 at 03:13 UTC
    even though I made socket FH non-blocking

    Where have you done this? I would have expected something like fcntl(FH, F_SETFL, $flags | O_NONBLOCK) but don't see anything like that. I'd try it out to see if it fixes your problem, but your code doesn't run on my machine ("Bad symbol for filehandle" on the accept($sock[$numsocks], FH) call.)
      I just tried using  fcntl(FH, F_SETFL, $flags | O_NONBLOCK);, but it gave me this error:

      Your vendor has not defined Fcntl macro F_SETFL, used at server.pl line 20.

      What do I do now? :-/
        You need to use the Fcntl module. Luckily, it's part of the core distribution. You might also look in perlopentut, under 'Opening Non-File Files'.

        Update: Move along, nothing to see here. My error is abundantly clear (He must have used Fcntl, which is why the fcntl() call didn't throw the error.) Oops.

      You can set it to nonblocking using setsockopt(). But i have one moer doubt please. How accept() will hang if it is blocking ? whether it is bblocking or non blocking it has to process the connect request fully and if there is any RST from clietnt also. Is it related with different clients connect requests?because in this case only this nonblock eill be usefull to process other client request instaed of hanging with one client Please clear my doubt. Thanks and Regards Jyothi Vajja