#!/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 () { 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: $_"; } }