#!/usr/bin/perl

use IO::Socket;

# Sucks in the command line arguments (resident in the array variable ARGV)
# and assigns them to the variables listed in ().  In this case, the first
# is the IP address of the machine on which the server is
# (hopefully) running.  The second is the port on which the server is 
# listening. 
	
($them,$port) = @ARGV;

# This checks to see if 'port' has been assigned a value and if it hasn't, 
# assigns the default port value 2345.   If 'them' (the machine on which
# the server is running) hasn't been assigned a value, 'localhost' is
# assumed.  This means that the server is on the same machine as the 
# client (us).

$port = 2345 unless $port;
$them = 'localhost' unless $them;

# This sets up a signal handler to kill the child we'll create later 
# in the event that we die

$SIG{'Int'} = 'dokill';

# This is a subprogram that does the killing.   The variable $child is
# initially undefined, so we won't try to kill a non-existant child.
# Later it will be the PID of the child we create.

sub dokill {
    kill 9, $child if $child;
}

# Strings in back quotes like `ls` run the Unix command inside the quotes
# and return the output.   The hostname command returns the name of the
# machine we're running on.   'chop' removes the newline character in the
# output from the hostname command.

chop($hostname = `hostname`);

# Looks up important information related to the network protocol you wish
# to use.   'tcp' is a connection-oriented protocol.  Look in 
# /etc/protocols for examples of others. Do NOT change this unless you
# know what you're doing.
	
($name, $aliases, $proto) = getprotobyname('tcp');

# This is a slightly different way of doing the service lookup that was
# done in the Server code.  Basically, if the specified port is an integer,
# the port number lookup isn't done, otherwise it is.

($name, $aliases, $port) = getservbyname($port,'tcp')
    unless $port =~ /^\d+$/;

# Let the user know what port we're using and where the server
# is expected to be, just in case (s)he accidentally typed an 
# incorrect port or machine name.

print "Using port $port to connect to server on host $them...\n";


# This looks up numeric IP address information corresponding to the 
# hostname for the current machine.

($name,$aliases,$type,$len,$thisaddr) = gethostbyname($hostname);

# This looks up numeric IP address information corresponding to the
# hostname where the server is expected to be running.

($name, $aliases,$type,$len,$thataddr) = gethostbyname($them);

#
# Socket creation
#

$ocket = IO::Socket::INET->new(	PeerAddr => $them,
						PeerPort => $port,
						Proto	 => "tcp",
						Type	 => SOCK_STREAM)
	or die "Couldn't connect to $them:$port : $@\n";



# Force our socket to flush output immediately after a print

#select(S);
#$| = 1;

# Make standard output the default again

#select(STDOUT);

# The interaction we want is to type lines of input and have them echoed
# back by the server.  But how can we both wait for input AND be receptive
# to the server's output?   Answer:  By forking a process to accept input
# from standard input (the keyboard) and send it to the server and using
# our current process to receive and display input from the server.

if ($child = fork) {
    
# We're the parent.  Read lines of input from the standard input and
# send them to the server until end of file is seen.
    
    while (<STDIN>) {
	print $ocket $_;
    }
    # Sleep for 3 seconds then...
    sleep 3;
    
    #...then kill ourselves and the child
    do dokill();
}
else {
    # We're the child.  Read lines of input from the server over the 
    # socket S and output them.   Stop if end of file is seen.
    
    while (<$ocket>) {
	print "Server: $_";
    }
}
