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

I am tearing my hair out over what ought to be a fairly simple thing. I am writing a client/server pair using IO::Socket. I started with the basics... I pass a command from client to server, the server parses the command, obtains a result, and passes the answer back to the client. The client receives the result and performs the appropriate action. I am happy. Moving onward, I want to perform the same actions multiple times, sending different commands from the client, but all other functionality being identical. I cannot get this to work at all. Whether I copy and paste code sequentially, or stick the code into a while loop, the server refuses to return any results to the client (or perhaps the client refuses to recieve them?). I have tried a few things, (Fcntl among them) and nothing seems to work right. What am I doing wrong? Is it even possible to go from read, to write, to read, to write on the same socket?

--
Believe nothing, no matter where you read it, or who said it - even if I have said it - unless it agrees with your own reason and your own common sense.
(Buddha)

Replies are listed 'Best First'.
Re: two-way socket works once only?
by ikegami (Patriarch) on Nov 23, 2004 at 18:35 UTC
    Is it even possible to go from read, to write, to read, to write on the same socket?"

    Yes, unless either end closes the socket. Reading and writting is completely independant. Do you have code to show us so we can help you debug? Don't forget to flush (or autoflush) commands and responses to make sure the other end gets it when you expect the other end to get it.

      Here's a example server and socket:

      server.pl

      use strict; use warnings; use IO::Socket (); my $listen_fh = IO::Socket->new( Domain => IO::Socket::AF_INET(), Proto => 'tcp', LocalAddr => '127.0.0.1', Listen => 1, ) or die("Unable to create listening socket: $!$/"); print('Listening on port ', $listen_fh->sockport(), '.', $/); my $client_fh = $listen_fh->accept() or die("Unable to accept a connection: $!$/"); print('Accepted a connection from ', $client_fh->peerhost(), ':', $cli +ent_fh->peerport(), '.', $/); while (<$client_fh>) { print $client_fh uc($_); } print('Connection closed by client or by error.', $/);

      client.pl

      use strict; use warnings; use IO::Socket (); my $peer_port = shift(@ARGV) or die("Specify the port on the command line.$/"); my $server_fh = IO::Socket->new( Domain => IO::Socket::AF_INET(), Proto => 'tcp', PeerAddr => '127.0.0.1', PeerPort => $peer_port, ) or die("Unable to connect to server: $!$/"); print('Connected to ', $server_fh->peerhost(), ':', $server_fh->peerpo +rt(), '.', $/); print('Type stuff to be uppercased by server. Blank line to exit.', $/ +); for (;;) { last if (!defined($_ = <STDIN>) || $_ eq $/); print $server_fh $_; last if (!defined($_ = <$server_fh>)); print; } print('Connection closed by server or by error or by request.', $/);
        I'm going over your code for clues that may help me. In the meantime, here is the code I am working on. Server.pl works fine as is, but if I try to put the code inside a while loop (I have tried both inside the socket open/close calls and outside) it quits working.

        edit: I changed my server.pl a bit based on what I saw in your example. This does not work. The while loop goes through the first iteration fine, and hangs up the second time through with a (error|warning) message of "Use of uninitialized value in substitution (s///) at /clocal/mptsgrp/user/mptsuser/scripts/guipartner.pl line 24, <GEN1> line 2."
        The print statements I included for debug show that $incoming matched /.+/ even after it was set to "" on the first iteration, but it did fail the $command[0] eq "check" test. The killer, though, is that the while loop stopped there. "Hi" was never printed a third time. :-(
        #!/usr/bin/perl use strict; use warnings; use IO::Socket; my $incoming; my $check; my @check; my @command; my $new_sock; my $sock = new IO::Socket::INET ( LocalPort => '8888', Proto => 'tcp', Listen => 1, Reuse => 1, ); die "Could not create socket: $!\n" unless $sock; $new_sock = $sock->accept(); while ($incoming = <$new_sock>){ print "hi"; if ($incoming =~ m/.+/){ print $incoming; @command = split / /,$incoming; $command[1] =~ s/\W+//g; $incoming = ""; if ($command[0] eq "check"){ $check = @check = `ps -ef |grep $command[1]`; print "$check\n@check\n"; if ($check >= 12) { print $new_sock "up"; } else { print $new_sock "down"; } }else{ print"did not work\n"; } } } close $sock;


        Likewise, the client works, so long as I don't duplicate the code to send a second request to the server.
        #!/usr/bin/perl use strict; use warnings; use IO::Socket; use Fcntl; my $input; my $sock; my $cs2; my $mqpcx; my $mpts; my $EOL = "\015\012"; my $BLANK = $EOL x 2; my $command; open OUT, "> testpage.html" or die "unable to write testpage"; ### OUT is temporary until I get cgi working. open FILE1, "< 1.html" or die; while (<FILE1>){print OUT} close FILE1; $sock = new IO::Socket::INET ( PeerAddr => '53.230.116.97', PeerPort => '8888', Proto => 'tcp', ); if ($sock){ print "Connection established\n"; $command = "check cs2" . $BLANK; print $sock $command; while ($cs2 = <$sock>){ last if ($cs2 =~ m/.+/); } if ($cs2 eq "up") { print OUT "<img src=\"./cs2up.gif\">\n"; $mpts++; print"so far, so good\n"; } elsif ($cs2 eq "down") { print OUT "<img src=\"./cs2down.gif\">\n"; } else { print "error getting data from other box"; } }else{ print OUT "<img src=\"./cs2down.gif\">\n"; print "no connection to other box"; } close($sock); close OUT; print "goodbye\n";

        --
        Believe nothing, no matter where you read it, or who said it - even if I have said it - unless it agrees with your own reason and your own common sense.
        (Buddha)