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

I'm trying to talk to the client from the server, until a predefined message is passed, like say "ok bye".
But my server speaks to the client only once, and then closes the connection.
Here's my server: #!c:\perl\bin\perl use IO::Socket; use IO::Select; use strict; my ($server, $client, $buf, $new_sock); my ($buf, $SOCK_STREAM, $server_port); { # Create a socket to listen on. my $listener=IO::Socket::INET->new( LocalPort => 21000, Listen => +2, Reuse => 2 ); die "Can't create socket for listening: $!" unless $listener; print "Listening for connections on port 21000\n"; my $readable=IO::Select->new; # Create a new IO::Select ob +ject $readable->add($listener); # Add the listener to it while(1) { # Get a list of sockets that are ready to talk to us. my ($ready) = IO::Select->select($readable, undef, undef, +undef); foreach my $s (@$ready) { # Is it a new connection? if($s == $listener) { # Accept the connection and add it to our readable + list. $new_sock = $listener->accept; $readable->add($new_sock) if $new_sock; print $new_sock "Welcome!\r\n"; + } else { # It's an established connection #print "established s $s listener $listener\n"; print $listener "Why don't you call me anymore?\n" +; $buf = <$s>; # Try to read a line print "$buf"; # Was there anyone on the other end? if (( defined $buf ) || ($buf =~ /\w/)) { # If they said goodbye, close the socket. +If not, # echo what they said to us. if ($buf =~ /goodbye/i) { print $s "See you later!\n"; $readable->remove($s); $s->close; } else { print $s "You said: $buf\n"; } } else { print $new_sock "Still there?\r\n"; # The client disconnected. $readable->remove($s); $s->close; print STDERR "Client Connection closed +, because you said $buf\n"; } } } } } My Client #!c:\perl\bin\perl use Socket; use IO::Socket; use strict; my ($remote_host, $remote_port); my ($internet_addr, $paddr); my ($soc, $answer, $socket); { use IO::Socket; $remote_host="localhost"; $remote_port=21000; #$soc=IO::Socket::INET->new("$remote_host:$remote_port") or die $@ +; $socket = IO::Socket::INET->new(PeerAddr => $remote_host, PeerPort => $remote_port, Proto => "tcp", Type => SOCK_STREAM) or die "Couldn't connect to $remote_host:$remote_port : $@\n"; #....do something with the socket do { print $socket "New host\n"; $answer=<$socket>; print $answer; }while ($answer =~ /end/); # Terminate the connection #close(TO_SERVER); close($socket); }
Thanks in advance!

Replies are listed 'Best First'.
Re: Socket Again!!!!
by pg (Canon) on Oct 17, 2003 at 04:09 UTC

    Just couple of small changes, and now both of your client and server are happy. I added my comments at each place I touched.

    • Your main problem was in your client, when you checking whether it should end, you used =~, which shall really be !~;
    • Couple of places you didn't check whether $buf is defined before you print, and I hate warnings, so added checking.
    • At one place you did try to check whether $buf is defined, but you did:
      if (( defined $buf ) || ($buf =~ /\w/))
      That logic was wrong, and it shall be:
      if (( defined $buf ) && ($buf =~ /\w/))
      In your logic, even if the first clause results false (not defined), Perl will still evaluate the second condition. In my logic, if the first condition results false, the second condition will not be evaluated, and that's what you really want.
    your server with my modification: use IO::Socket; use IO::Select; use strict; my ($server, $client, $buf, $new_sock); my ($SOCK_STREAM, $server_port); #pg: remove $buf, defined twice. { my $listener=IO::Socket::INET->new( LocalPort => 21000, Listen => +2, Reuse => 2 ); die "Can't create socket for listening: $!" unless $listener; print "Listening for connections on port 21000\n"; my $readable=IO::Select->new; $readable->add($listener); while(1) { my ($ready) = IO::Select->select($readable, undef, undef, +undef); foreach my $s (@$ready) { if($s == $listener) { $new_sock = $listener->accept; $readable->add($new_sock) if $new_sock; print $new_sock "Welcome!\r\n"; + } else { print $listener "Why don't you call me anymore?\n" +; $buf = <$s>; print "$buf" if (defined($buf)); #pg: added if def +ined if (( defined $buf ) && ($buf =~ /\w/)) #pg: it wa +s || { if ($buf =~ /goodbye/i) { print $s "See you later!\n"; $readable->remove($s); $s->close; } else { print $s "You said: $buf\n"; } } else { print $new_sock "Still there?\r\n"; $readable->remove($s); $s->close; print STDERR "Client Connection closed +, because you said $buf\n" if (defined $buf); #pg: added checking for + defined $buf } } } } } your client with my modification: use Socket; use IO::Socket; use strict; my ($remote_host, $remote_port); my ($internet_addr, $paddr); my ($soc, $answer, $socket); { use IO::Socket; $remote_host="localhost"; $remote_port=21000; $socket = IO::Socket::INET->new(PeerAddr => $remote_host, PeerPort => $remote_port, Proto => "tcp", Type => SOCK_STREAM) or die "Couldn't connect to $remote_host:$remote_port : $@\n"; do { print $socket "New host\n"; $answer=<$socket>; print $answer; }while ($answer !~ /end/); #pg: was =~, it shall really be !~ close($socket); }
      Bows... With the right hand touching the chest!
      One more question pg ....
      You had given me a same example using threads...
      Suppose you had to choose between the threads and the set of the scripts above, which will it be?
      Thanks!

      (Bows again ;-) )

        Depends on, if you only expect one client (or one client a time), your way is just fine. If you expect multiple clients talking to the server at the same time (and client might come and go ), then sooner or later you have to go with thread. For this kind of application, using thread makes your code more neat, clear, easy to understand, and easy to maintain.

        Play with thread. If you have problem with threading, come and ask, someone here will help.