Lab 4 due 12:01 am, Saturday, June 4th, 2011 20 points. Your programs should be called server.pl and client.pl. You will write a simple client and server using perl's IO::Socket::INET module. Your server should open a socket as discussed in class, read lines from the client, and close the connection when you read a line that contains the string: DONE That line should NOT be included in the lines that you use for the next portion of the lab. Your server should assume that each line that is sent to it is of the following format (unless it includes the string DONE of course): Key: Value Key and Value must match \w+, and there must be a colon and one space after the Key before it gets to the value. If the line does not match this, throw it out. Once you have disconnected the client, you should produce the following reports on the data: NOTE- all non-numerical sorts should be ASCII-betical ------- sorting requirements ------- A1. Sort all the keys by name and display them along with their values then wait for input from the user (we will throw this input out- it's simply a read with <>) A2. Sort all the keys according to their values, with the extra restriction that if a value contains anything other than numbers, we'll just ignore that pair for this part- then again wait for a dummy input of the user before exiting. Ties for number value will be resolved by a simple ascii cmp on the Key. The following data: Blood => 234 Blooe => 234 Fire => 55 Death => 88 should be sorted like this: Fire => 55 # lowest number Death => 88 # middle number Blood => 234 # highest number Blooe => 234 # highest number, and Blooe cmp Blood == 1 ------ command line -------- Your server should check for one command line argument which is the port to listen on. So it will be called like this: ./server.pl 5000 or something similar. Keep in mind that you can't bind to ports below 5000 if you are not the user known as root (at least on unix). So, for testing, be sure to use port numbers of 5000 or above. As for the client, you should accept THREE arguments- no more, no less. They will be as follows: ./client.pl hostname port inputfile The hostname and the port will be used to make a connection to the server. The inputfile will be a textfile that you will read that will have data corresponding exactly to the format discussed above: Key: Value Any lines in the file which do NOT conform to this standard will just be ignored (unless you are doing extra credit of course). The client DOES need to check to make sure that 3 arguments are passed, and it needs to check the usual things like the ability to open the inputfile, and the ability to connect to the server- if either of these fail, it should exit with an appropriate error message. ------ important notes -------- 1. your job will be made much simpler in your client if you remember to send a \n at the end of every line you send to the server. The IO::Socket:INET->flush() method also works for this. Either of these methods should flush out the input buffer and force your server to read the line. 2. your server may encounter some strange end of line characters- if you do the following for each line: # remove all trailing whitespace characters from the line $line =~ s/\s+$//; you should be fine. 3. writing the server first might be your best bet- your server must use the hostname function from Sys::Hostname to spit out the name of the machine you are running on (remember that stdsun is not actually the name of a machine- you WILL need to know the particular server name that your server is running on)- you can telnet to your server to get it working in the following way: ./server.pl 5006 (server prints out Hostname: lamda) telnet lambda 5006 (type in some lines that correspond to the specs) (type in DONE) (server processes them and spits out the sorts that I asked for, you will need to hit enter a few times in the server's terminal window to see all of them) (hit ctrl-] to get to telnet prompt) (type quit at telnet prompt) Notice in this example that I run the server first, it tells me which hostname it is running on, and then I connect to it with telnet for testing. You should also use this method to determine the first command line argument to your client, which is the hostname to which you want to connect. 4. I suggest you write all of the code for this on unix- I know all of these tips work on unix- I can't vouch for windows. 5. Start on this lab early... 6. Since the important thing here is that you get exposed to some of the applications of perl, and since most of the class indicated that they had no familiarity with basic networking code, here are some skeletons to get you started: -------------- basic client ------------------ #!/usr/local/bin/perl -w use strict; use IO::Socket; # note that you will have to do your command line processing, # and your opening of the input file, and reading from it - this # example code just sets up a socket to a hard-coded machine # and port, and prints a test line to it my $s = IO::Socket::INET->new("somehost:someport") or die $@; # set up autoflushing select $s; $|++; print $s "This message is sent through the socket to the server\n"; print $s "DONE\n"; close ($s); -------------- basic server -------------------- #!/usr/local/bin/perl -w use strict; use IO::Socket; use Sys::Hostname; # you will have to figure out your hostname, print out the # appropriate info to the user, read the lines from the client # and print out the sorted results on your own- this just shows # the reading of the two lines from the sample client above my $port = 5000; my $server = IO::Socket::INET->new(LocalPort => $port, Type => SOCK_STREAM, ReuseAddr => 1, Listen => 1) or die $@; my $client = $server->accept(); while (my $stuff = <$client>) { chomp $stuff; if ($stuff =~ /DONE/) { print "The client told us we were done\n"; last; } print "The client sent us a line that contained: $stuff\n"; } close($client); close($server); ------- Extra Credit: 1. (8) Do a more complicated sort AFTER requirement A2 above: sort the data by value, putting anything that consists of all numbers highest in the list, followed by anything that contains at least one number (but also other \w characters), followed by anything else (\w without \d). You should sort the numbers with <=>, and the other two groups by ascii sort. Remember that you are sorting based on the values, but you will still show all the rows as key value pairs. Ties for values will be resolved by a simple ascii cmp of the Key. The following data: Fire: => asldkjf Blood: => 1234 Death: => 12ab5 Beer: => 55 Wine: => 12aa would be output this way: Fire => asldkjf # non-numbers are lowest priority Wine => 12aa # follwed by "contains some numbers" Death => 12ab5 # 12ab5 cmp 12aa is 1 Beer => 55 # followed by numbers Blood => 1234 # 1234 is greater than 55 Blooe => 1234 # cmp says Blooe is higher than Blood So, to rephrase, the highest number has highest priority, then all the rest of the numbers, then the "highest" (based on cmp) of the strings that include some numbers and some non-numbers, then followed by the "highest" (again based on cmp) of the strings, and then on down the list of the rest of the strings. If you get this one completely right it will be worth a good amount of extra credit... 2. (4) practice a schwartzian transform All of the work for this part will be done in the server, since the key => value pairs will still be legal according to the normal definition. Treat all the keys and values as normal for the two required sorts as well as e.c. #1 if you are doing it, but also do the following: Treat anything that has a key like SSNddddddddd as a social security number to last name mapping. For example, if two of your key, value pairs are: SSN333555444: Jones SSN321555444: Smith then the person with ssn 333555444 has a last name of Jones, and the person with ssn 321555444 has a last name of Smith. Then, treat any keys corresponding to: ddddddddd: \d+ as ssn to score mappings. So adding to the items above, we have: 333555444: 55 321555444: 65 So Jones got a 55 for his score, and Smith got a 65. Now for the sort- produce a sort of all of the ssn-like keys, based on Last name- you will of course show the scores as well, but your output should be in ascending asciibetical order by last name. A sample output for this could be (with a few more ssns added): Akbar: 75 Jones: 55 Smith: 65 If there are two last names, don't worry about breaking the tie- you just need to sort based on last name. Use a Schwartzian transform for this.