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.

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