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

Morning Monks - I hope you can help me with a few issues I have with client/server behaviour on windows using TK Perl and sockets. The code below works fine on Linux however when I try and port over to windows I just can't get the client to connect to server. The idea is to launch 2 windows with text widgets that you can enter text to go back and forth between client/server an update the log. Once I can get this working I will move it into an application. Below I have attached the client server code : Client.pl
#!/usr/bin/perl use warnings; use strict; use Tk; use IO::Socket; require Tk::ROText; use Data::Dumper; # create the socket my $host = shift || 'localhost'; my $port = 7070; my $socket = IO::Socket::INET->new( PeerAddr => $host, PeerPort => $port, Proto => 'tcp', ); defined $socket or die "ERROR: Can't connect to port $port on $host: $ +!\n"; print STDERR "Connected to server ...\n"; my $mw = new MainWindow; my $text = $mw->Scrolled('Text', -background =>'black', -foreground => 'yellow', )->pack(); my $txt = $mw->Entry()->pack(qw/-fill x -pady 5/); $mw ->bind('<Any-Enter>' => sub { $txt->Tk::focus }); $txt->bind('<Return>' => [\&broadcast, $socket]); $mw ->fileevent($socket, readable => sub { my $line = <$socket>; unless (defined $line) { $mw->fileevent($socket => readable => ''); return; } $text->insert(end => $line); }); $mw->fileevent($socket, 'readable', sub { handle_connection($socket) } +); MainLoop; sub broadcast { my ($ent, $sock) = @_; my $text = $ent->get; $ent->delete(qw/0 end/); $sock->print("$text\n"); } sub handle_connection { my ($client) = @_; my $message = <$client>; if (defined $message and $message !~ /^quit/) { $message =~ s/[\r\n]+$//; $text->insert('end', "Got message [$message]\n"); $text->see('end'); } else { $text->insert('end', "Connection Closed\n"); $text->see('end'); $client->close(); } }
Server.pl
#!/usr/bin/perl use warnings; use strict; use Tk; use IO::Socket; require Tk::ROText; use Data::Dumper; # create the socket my $host = shift || 'localhost'; my $port = 7070; my $socket = IO::Socket::INET->new( LocalPort => $port, Listen => 1, Reuse => 1, Proto => 'tcp', ); defined $socket or die "ERROR: Can't connect to port $port on $host: $ +!\n"; my $mw = new MainWindow; my $text = $mw->Scrolled('Text', -background =>'black', -foreground => 'yellow', )->pack(); my $txt = $mw->Entry()->pack(qw/-fill x -pady 5/); $mw ->bind('<Any-Enter>' => sub { $txt->Tk::focus }); $txt->bind('<Return>' => [\&broadcast, $socket]); $mw ->fileevent($socket, readable => sub { my $line = <$socket>; unless (defined $line) { $mw->fileevent($socket => readable => ''); return; } $text->insert(end => $line); }); my $client; $mw->fileevent($socket, 'readable', sub { new_connection($socket) }); MainLoop; sub broadcast { my ($ent, $sock) = @_; my $txt = $ent->get; $ent->delete(qw/0 end/); $text->insert('end', "Sending [$txt]\n"); $text->see('end'); $client->print("$txt\n"); } sub new_connection { my ($listen) = @_; $client = $listen->accept() or warn "Can't accept connection"; $client->autoflush(1); $mw->fileevent($client, 'readable', sub { handle_connection($clien +t) }); $client->print("Connected\n"); $text->insert('end', "Connected\n"); $text->see('end'); } sub handle_connection { my ($client) = @_; my $message = <$client>; if (defined $message and $message !~ /^quit/) { $message =~ s/[\r\n]+$//; $client->print("successfully sent $message\n"); $text->insert('end', "Got message [$message]\n"); $text->see('end'); } else { $text->insert('end', "Connection Closed\n"); $text->see('end'); $client->close(); } }

Replies are listed 'Best First'.
Re: Client/Server sockets with TK on Win32
by zentara (Cardinal) on Apr 16, 2012 at 13:11 UTC
    I don't have Windows, and your scripts run on Linux; but it seems you have 2 fileevents on the $socket filehandle. That does not look right, as it may prevent the new_connection sub from getting triggered.

    Also there is a faq for this at ActiveState Windows socket faq, which may have a clue for your version of Windows.

    $mw ->fileevent($socket, readable => sub { my $line = <$socket>; unless (defined $line) { $mw->fileevent($socket => readable => ''); return; } $text->insert(end => $line); }); my $client; $mw->fileevent($socket, 'readable', sub { new_connection($socket) });

    I'm not really a human, but I play one on earth.
    Old Perl Programmer Haiku ................... flash japh
Re: Client/Server sockets with TK on Win32
by BrowserUk (Patriarch) on Apr 16, 2012 at 13:36 UTC

    With your code unchanged, the client connects to the server just fine (Vista-64/AS5.10.1-64).

    After that, not much seems to happen, but with two different subs attached to the readable event, and an absence of error checks that doesn't surprise me.

    I'm also a bit surprised that the code works as-is on *nix.

    I'd also have expected you to have to set the sockets non-blocking for the fileevent stuff to work.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    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.

    The start of some sanity?

      there are two text boxes at the bottom of each window taking an input. This text input "should" be passed from client/server
        there are two text boxes at the bottom of each window taking an input. This text input "should" be passed from client/server

        I appreciate that. All I said was that the connection is established.

        In contradiction to the claim in the OP -- "however when I try and port over to windows I just can't get the client to connect to server. " -- the the client *does connect to the server*.

        However, beyond that I don't know enough about Tk fileevents to debug the rest of the code. I can see from reading the POD that it says

        "However, there may be at most one readable and one writable handler for a file at a given time in a given interpreter. If fileevent is called when the specified handler already exists in the invoking interpreter, the new callback replaces the old one."
        -- which means that even if teh code "works on Linux", it is broken as posted.

        The POD also says:

        "Event-driven I/O works best for filehandles that have been placed into nonblocking mode. In blocking mode, a print command may block if you give it more data than the underlying file or device can accept, and a <>, sysread or read command will block if you attempt to read more data than is ready; no events will be processed while the commands block. In nonblocking mode print, <>, sysread and read never block. See the documentation for the individual commands for information on how they handle blocking and nonblocking filehandles."
        -- which suggests that it probably isn't "working on Linux" as posted.

        The POD also says:

        "BUGS

        On windows platforms fileevent is limited in the types of filehandles that behave correctly. Making filefhandles non-blocking is only implemented on a subset of UNIX platforms (see the Tk::IO manpage).

        -- which further suggests that the code as posted is broken.

        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        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.

        The start of some sanity?

Re: Client/Server sockets with TK on Win32
by halfcountplus (Hermit) on Apr 16, 2012 at 13:15 UTC
    I just can't get the client to connect to server

    So what did $! say about that?

Re: Client/Server sockets with TK on Win32
by merseyred (Initiate) on Apr 16, 2012 at 14:23 UTC
    The issue seems to be that the server doesn't seem to be calling new_connection from the fileevent call.
      The issue seems to be that the server doesn't seem to be calling new_connection from the fileevent call.

      Then comment out your first fileevent and see what happens. Your text handling should be done in the handle_connection subroutine.

      Below is how the server code should look, I don't know how you got it so confused. Notice how clients get created in new_connection, and handled by handle_connection.

      #!/usr/bin/perl use strict; use warnings; use IO::Socket; use Tk; $|=1; $SIG{PIPE} = 'IGNORE'; my $listen = IO::Socket::INET->new( Proto => 'tcp', LocalPort => 7070, Listen => 1, Reuse => 1, ) or die "Can't create listen socket : $!\n"; my $mw = MainWindow->new(); my $text = $mw->Scrolled('Text', -background =>'black', -foreground => 'yellow', )->pack(); my $subframe = $mw->Frame()->pack(); $subframe->Button(-text => 'Clear', -command => sub { $text->delete('1.0','end'); })->pack(-side=>'left'); $subframe->Button(-text => 'Save Log', -command => sub { })->pack(-side=>'left'); $subframe->Button(-text => 'Exit', -command => sub { exit })->pack(-side=>'right'); $mw->fileevent($listen, 'readable', sub { new_connection($listen) }); Tk::MainLoop; sub new_connection { my ($listen) = @_; my $client = $listen->accept() or warn "Can't accept connection"; $client->autoflush(1); $mw->fileevent($client, 'readable', sub { handle_connection($clien +t) }); $client->print("Connected\n"); $text->insert('end', "Connected\t"); $text->see('end'); } sub handle_connection { my ($client) = @_; my $message = <$client>; if (defined $message and $message !~ /^quit/) { $message =~ s/[\r\n]+$//; $client->print("Got message [$message]\n"); #echo back if wanted $text->insert('end', "Got message [$message]\t"); $text->see('end'); } else { $text->insert('end', "Connection Closed\n"); $text->see('end'); $client->close(); } }

      I'm not really a human, but I play one on earth.
      Old Perl Programmer Haiku ................... flash japh

        Even with your (very sensible) modification, under windows, the listener's readable event handler is never called. Even though the connection from client to server is established. And even if the listener socket is set nonblocking.

        My conclusion is that Tk fileevents simply do not work on windows.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        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.

        The start of some sanity?

Re: Client/Server sockets with TK on Win32
by zentara (Cardinal) on Apr 18, 2012 at 16:31 UTC