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

I am working on a client for a game, in Perl/Tk. My goal, and reasoning for using Perl/Tk, is to have it as portable as possible.

In the application, I need to read from sockets in a non-blocking fashion. On unix, setting $socket->blocking(0); works like a charm. It doesn't seem to work like that on Windows (running ActivePerl - is there a better solution?).

So, I must do it the 'brute force' method and use fcntl to set non-blocking mode. Yet, when I try to use fcntl on Windows, it tells me "fcntl is not implemented at ..." then quoting the line number on the file it is called.

I tried using POSIX and trying to use the fcntl in POSIX .. to the same problem.

Is fcntl implemented on Windows? Otherwise, is there another solution to set the $socket to non-blocking mode?

Daimun

Replies are listed 'Best First'.
Re: fcntl on Windows
by Adam (Vicar) on Mar 21, 2001 at 00:49 UTC
    Yes, you can get fcntl on windows*. As for using it to do non blocking, I have to admit that I've never done it in Perl. But here is how I do it in C, and I suspect that the Perl way is almost identical:
    #include <stdio.h> #include <fcntl.h> void SetNonBlocking( int filehandle ) { int fhFlags; fhFlags = fcntl(filehandle,F_GETFL); if (fhFlags < 0) { perror("fcntl(F_GETFL)"); exit(1); } fhFlags |= O_NONBLOCK; if (fcntl(filehandle,F_SETFL,fhFlags) < 0) { perror("fcntl(F_SETFL)"); exit(1); } return; }
    Update:
    We discover this later in this thread, but rather deep, so I'll reiterate it here. It turns out that the fcntl module is available on Win32, but not fcntl(2) the method. That is *nix specific. Camel2 states, "fcntl will produce a fatal error if used on a machine that doesn't implement fcntl(2)."

    My new recomendation is to use select to poll the socket, and when it has data, then read from it blocking. You can simulate non-blocking by using a small timeout on the select and only reading a few charaters (or even just 1) at a time.


    *Note that the standard distribution uses the local c compiler to create Fcntl.pm during install. It is possible then, that someone might not have Fcntl.pm, however ActiveState's distribution of Perl does include it.
      The point was not to figure out how to do it.. I know how to do it.. Here is my 'test' code.

      #!/usr/bin/perl use IO::Socket; $sock = IO::Socket::INET->new( PeerAddr => '192.168.0.4', PeerPort => 4000, Proto => 'tcp' ); $flags = fcntl($sock, F_GETFL, 0) or die "Can't get flags for socket: $!\n"; fcntl($sock, F_SETFL, $flags | O_NONBLOCK) or die "Can't make socket nonblocking: $!\n"; print $sock "logn 0607daimuntemp123\n"; while(1) { sleep 1; $str = <$sock>; chomp $str; print $str . "\n"; if( $str =~ /^$/ ) { print "null\n"; } }


      When run, it results in this error:
      fcntl is not implemented at sam.pl line 10.

      Daimun
        You forgot the line:
        use Fcntl;
        Easy mistake to make. That should fix it.

        Update:
        I tried your code (plus the use statement and a few print statements) on my NT box with Perl 5.6 and got this rather annoying message:

        Your vendor has not defined Fcntl macro F_GETFL, used at C:\temp.pl li +ne 10.
        That means the Fcntl implementation in my install is incomplete. I suspect this is going to be true across Windows installations, so you might want to write a wrapper around Fcntl that defaults to Fcntl but fills in the holes when they are missing.
(tye)Re: fcntl on Windows
by tye (Sage) on Mar 21, 2001 at 05:05 UTC

    You can make a socket non-blocking under Win32 via the WSPIoctl() API. More details tomorrow...

            - tye (but my friends call me "Tye")
Re: fcntl on Windows
by kschwab (Vicar) on Mar 21, 2001 at 08:37 UTC
    Since you are already using Tk, you may be interested in Tk::Fileevent and Tk::IO.

    These give you a more generalized way of handling file and socket i/o in a gui event loop. (Basically placing a select() call for you in the gui event loop, you just supply a callback) Do read the CAVEATS and WARNINGS sections though.

Re: fcntl on Windows
by howard40 (Beadle) on Mar 21, 2001 at 03:50 UTC
    have you looked at the can_read function of the IO::Socket class? it accepts a value in seconds to wait before timing out and proceeding with the rest of the script.
    for example, this (untested) will wait 1 second and then move on.

    my $sel = $sock->select; $sel->can_read(1);
      I can't seem to find any such can_read function in IO::Socket. Do you know of any documentation on it?

      Daimun
Re: fcntl on Windows
by Daimun (Novice) on Mar 21, 2001 at 22:25 UTC
    I'd like to thank everyone whom offered help with this dilemma. I've decided the most prudent solution will be usnig a Select, as it will enable me to keep the code fairly unified, with a few simple checks to determine if it's running in a non-posix environment.

    - Daimun