Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Socket programming

by Anonymous Monk
on Oct 06, 2000 at 13:39 UTC ( #35554=perlquestion: print w/ replies, xml ) Need Help??
Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Trying to code the following:

One program is the main program, which fork/execs one referee process and two player processes. It then waits until all three terminate. It should check that the command line parameter specifies the number of games is legal and pass it to the referee process as a parameter to exec().

One program is a referee program, which playes the role of a server. This program should prepare a socket and then listen to both players to send the string ``READY'', which means that they're ready to make a choice. It should then tell each player to make a choice by sending them both the string ``GO''. Their responses are then read, and their scores are calculated and updated. This process should be repeated until all of the turns have been taken, at which point the referee should send both players the string ``STOP'', which causes them to terminate.

One program is a a player program, which playes the role of the client. This program is executed twice by the main program, and should start by connecting to the referee's socket. It should then send the ``READY'' message. When it receives the ``GO'' message back from the referee, it should make a choice anbd send it as a stringto the referee. When it receives the string ``STOP'', it should kill itself.

Here's what I have so far:

Here's the main program "play":

#!/usr/bin/perl die "Invalid number of games" unless ($ARGV[0] > 0); system "./server $ARGV[0] &"; sleep 1; $pid = fork(); die "unable to fork: $!" unless defined $pid; exec "./client &";
Here's the referee "server":
#!/usr/bin/perl use IO::Socket; $server = IO::Socket::INET->new( Proto => 'tcp', LocalHost => 'localhost', LocalPort => '6969', Listen => 1, Reuse => 1); die "can't setup server" unless $server; print "[Server $0 accepting clients]\n"; while ($client = $server->accept()) { while (<$client>) { if ($play_game) { #play game in here } elsif (/READY/i) { $players_ready++; } if ($players_ready == 2) { print $client "GO\n"; $play_game = +1; } } close $client; }
Here's the player "client":
#!/usr/bin/perl -w use IO::Socket; # create a tcp connection to the specified host and port $client = IO::Socket::INET->new( Proto => "tcp", PeerAddr => 'localhost', PeerPort => '6969' ), or die "can't connect to server: $!"; print "[Client $0 connected to server]\n"; print $client "READY\n"; while ($server = $client->accept()) { while (<$server>) { if (/GO/i) { srand; # seed the random number function $num = int (rand 4); # get a random integer, 1 through 104 if ($num == 1) { print $server "Rock\n"; } elsif ($num == 2) { print $server "Paper\n"; } elsif ($num == 3) { print $server "Scissors\n"; } } if (/STOP/i) { last; } } close $server; }
My problem is in getting the server program to communicate with the client.

Here's what I know:

When I run "play", the server receives the 2 "READY" signals from the clients and the following code line DOES get executed:

if ($players_ready == 2) { print $client "GO\n"; $play_game = 1; }
However, the if (/GO/i) conditional in the client program is not getting executed and I do not know why. Is it something simple or is bi-directional communication really harder than I originally thought?

My only guess is that somehow I'm not sending the "GO" message properly. I just don't understand why the server was able to receive the "READY" with no problem, but the client is choking on the "GO". Any help would be much appreciated.

Magius_AR

Comment on Socket programming
Select or Download Code
RE: Socket programming
by Magius_AR (Sexton) on Oct 06, 2000 at 13:40 UTC
    whoops, forgot to log in first :> my bad :)
Re: Socket programming
by Jonathan (Curate) on Oct 06, 2000 at 14:52 UTC
    I would change the client side
    #!/usr/local/bin/perl use IO::Socket; # create a tcp connection to the specified host and port $server = IO::Socket::INET->new( Proto => "tcp", PeerAddr => 'localhost', PeerPort => '6969' ), or die "can't connect to server: $!"; print "[Client $0 connected to server]\n"; print $server "READY\n"; while (defined ($this_line = <$server>)) { print STDOUT $this_line; if ($this_line =~ /STOP/i) { last; } } close $server;


    connects ok. On the server side I like to run with autoflush on. e.g. adding use FileHandle; and then $server->autoflush(1); after you have opened the socket. I believe select $server;$|=1 will do the same thing. <BR

    "We are all prompted by the same motives, all deceived by the same fallacies, all animated by hope, obstructed by danger, entangled by desire, and seduced by pleasure." - Samuel Johnson

      Just a little heads-up, from IO::Socket's docs:

      As of VERSION 1.18 all IO::Socket objects have autoflush turned on
      by default. This was not the case with earlier releases.


      So no need for toggling the buffering.

      Cheers!
Re: Socket programming
by AgentM (Curate) on Oct 06, 2000 at 23:17 UTC
    As a speed issue, you should definitely consider a better form of IPC. You say that you fork off the server and clienst, this will probably mean that they're on the same computer ;so using a TCP socket is a real waste of time and complicates things unnecessarily. You guys are even giving him advice against a local domain socket (UNIX domain socket) which will speed up the communication by at least a factor of 6! Of course, the fastest IPC is shared memory created by memory mapping a file (mmap). But judging by your current design, you should go for semaphores in shared memory or the current library that provides system-wide semaphores (which will take care of the mmap). On POSIX systems, this will be <semaphore.h> and perl supports only SysV sems via IPC::Semaphore (for those crappy and bulky SysV semaphores) or you can try the Thread::Semaphore which does not require you to have any more than one thread and simplifies things quite a bit though it does not provide system-wide sems. Just remember to make them systemwide for your multiple processes (which on POSIX systems will become a path and on SysV an IPC object viewable with -wow- ipcs at the command line! Remember, THERE IS NO REASON TO USE SOCKETS ON THE SAME COMPUTTER (sic). (Exception: generic client not optimzed for use on same computer, only multiple computers which is the way most games are setup so it's not waiting on I/O on a socket and some other IPC.) If you really want to get intense, you'll check out IPC::Msg which is probably more than you need for this simple client/server arrangement. (Most systems provide also for system-wide pipes called FIFOs.)
    I see this only all too often. A lack of POSIX functions forces me to revert to C/C++. O, shame! Perhaps I'll extend the POSIX library which is very poorly arranged indeed!
    AgentM Systems or Nasca Enterprises is not responsible for the comments made by AgentM- anywhere.
RE: Socket programming
by Zarathustra (Beadle) on Oct 07, 2000 at 04:58 UTC

    Looks like your mistake is using the accept method in your client.

    Don't do that.

    (c8=

    #!/usr/bin/perl -w use IO::Socket; # create a tcp connection to the specified host and port $client = IO::Socket::INET->new( Proto => "tcp", PeerAddr => 'localhost', PeerPort => '6969' ), or die "can't connect to server: $!"; print "[Client $0 connected to server]\n"; print $client "READY\n"; # as a client, you are not accepting connections # while ($server = $client->accept()) { # listen on and talk into your open socket instead while (<$client>) { if (/GO/i) { srand; # seed the random number function $num = int (rand 4); # get a random integer, 1 through 104 if ($num == 1) { print $client "Rock\n"; } elsif ($num == 2) { print $client "Paper\n"; } elsif ($num == 3) { print $client "Scissors\n"; } } if (/STOP/i) { last; } } close $client;

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://35554]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (5)
As of 2014-09-03 00:12 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My favorite cookbook is:










    Results (34 votes), past polls