http://www.perlmonks.org?node_id=1057201

Reading Perl related blogs recently, I ran into Games in Perl/Tk. At that moment I remembered I had also created a Tk based game. I searched the hard disk and web and found out it was ten years ago when I created chalaxy (I created a git repository for it few days ago). I wrote it for 5.6.1 we were running at the university.

The game had a small bug. It rarely manifested itself, so I was not able to fix it (at that time): If there were several players and the game board was larger, sometimes a player did not get all the information from the server. See poorly documented behaviour of readline() and IO::Select for a similar problem - and even for my reply about the solution I implemented: I just added a one second sleep after each line written to the server, which was usually enough for the server to read the line.

After reading the blog post about Perl games, I decided to fix the game. I spent several days searching the internet and trying different solutions, but I was not able to make it work.

There are two phases of the communication between the server and the clients:

  1. The server waits for new connections. Once accepted, each client sends its "name" to the server and waits for further instructions (phase 2). Once all the players are connected, the second phase is started.
  2. Clients send messages to the server and the server sends messages to clients. There is no order, the GUI should not freeze waiting for a message.

Most examples you can find around the Internet deal with a simpler model: the server waits for connections, once a client connects, it handles its requests, then the client is disconnected and the server continues. In my scenario, the clients do not disconnect before the game ends.

The server used IO::Select to detect incoming messages, the clients used Tk::fileevent. When I removed print and readline from the code and used syswrite and sysread instead, the code worked fine on MS Windows, but it still did not run correctly on Linux: it seemed as if sysread was blocking on Linux but not on Windows when the handle was empty. I still do not understand what the exact problem was, but I was able to work around it.

I had to write my own buffering (because I did not want to change the logic). Because of that, the fileevent was not enough and I had to add a Tk::repeat fetching from the buffer. The solution is not yet correct because I do not buffer on the writing side, but the messages are rather short and the game works.

لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

Replies are listed 'Best First'.
Re: A Game Using TCP Sockets
by marinersk (Priest) on Oct 07, 2013 at 08:15 UTC
    LOL.

    Leave it to you, choroba, to find a way to motivate me to reinstall Tk.pm after my recent upgrade:

    Can't locate Tk.pm in @INC (@INC contains: C:\Steve\Perl C:/Perl/Perl- +5.16.3.1603/site/lib C:/Perl/Perl-5.16.3.1603/lib .) at chalaxy-cl li +n e 15. BEGIN failed--compilation aborted at chalaxy-cl line 15.

    Okay, now where did I put those crib notes about how to install CPAN modules, again?

    /me wanders off, muttering to self incoherently . . .

      Both chalaxy-ser and chalaxy-cl have shebang lines of #!/usr/bin/perl, so you may want to run them as:

      /path/to/your/normal/perl chalaxy-ser /path/to/your/normal/perl chalaxy-cl

      That's what I did when I got the same "Can't locate Tk.pm ..." message. I already had Tk installed.

      -- Ken

Re: A Game Using TCP Sockets
by atcroft (Abbot) on Oct 14, 2013 at 03:55 UTC

    I saw the comments on this thread, and decided to pull a copy of the repo and see what it looked like. I launched the server on Win7 under Cygwin. My first thought was that it would be nice to be able to use Getopt::Long (or another similar module) to pass in the appropriate values. When starting the server, I hit enter to select the default values, but received an uninitialized value message for line 35 ($planetNum ?). I think the message may relate a missing 'q' operator:     $planetNum = 10 if $planetNum = ();-did you mean q() instead?

    Still looking through the code, but hope the remarks above prove helpful.

    Update: 2013-10-14 Corrected line number of affected code.

      Thanks for the notice. The "uninitialized message" is just a warning, in fact
      print q()eq();

      outputs 1, but your explanation is correct - it should have been q(). (Also note = versus eq).

      لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: A Game Using TCP Sockets
by oiskuu (Hermit) on Oct 14, 2013 at 02:46 UTC

    Ahem, I took another look at the game, just ignore my previous rambling.
    Discovered the following though:

    } elsif ($get =~ /MESSAGE ([^ ]+) (.*)\n$/) {
    This pattern can never match since the line is chomped?

    Why is Tk::repeat necessary, what happens if it's omitted?
    Update: ah, I see it now. Why don't you modify get_line to return all lines available if wantarray?
    Process could then do ... for my $get (get_line($server)) {} ...

      Have you seen the code? sysread is looped. readline was not working correctly - after reading a line, the following lines might end in a buffer, from which you never retrieve them, as the handle is no longer readable.

      Update: Maybe I did not understand your point. Please, show some code: how should I loop sysread? What should be the condition of the loop, to avoid blocking?

      لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ