Client
Clients using the exchanger send a message of the following format:
SWAP stuff USING key
This should result in a response of the form:
RETURN stuff USING key
The stuff
and key
are any words consisting of characters that aren’t white space.
If a message is sent that isn’t in the proper format, the response should be an exclamation point followed by the original message. For example, if the following message is sent.
!This is a very, very bad message!
This should be the response:
!!This is a very, very bad message!
We will follow the convention of having lines terminated by CRLF
,
or '\r\n'
, in line-oriented networking protocols,
such as HTTP.
Unfortunately, it can be a little difficult to generate
a real CRLF
in
some
programming language and platforms.
To avoid this program, try using the following two routines when you are using Python.
def getNetLine(netinstr): try: inline = netinstr.readline() # up to \n or EOF if (inline[-2:] == '\r\n'): # CR LF -- usual case return inline[:-2] if (inline[-1:] == '\n'): # LF -- being tolerant return inline[:-1] return '' # closed connection except: raise def putNetLine(netoutstr, line): try: netoutstr.write(line + '\r\n') netoutstr.flush() except: raise
Server
Ultimately, the server will allow pairs of clients to swap
stuff
, but we are going to proceed in small steps.
Step 1 — Homework 2
Write a server the reads lines from a client and echoes with
SWAP
replaced with RETURN
.
Your client should run on TCP port
33101 and needs to accept only one client at a time.
Step 2 — Homework 3
Modify your server so that it could accept several clients simultaneously.
In Python, you’ll need to use either the difficult
threading
or the dreaded select
interface to do this.
Step 3 — Homework 6 — Repeater
The repeater is a hardened version of the Step 2 solution. It parses good messages and returns an appropriate response. It returns a bad messages with the prefixed exclamation point.
There is a repeater running at port 33101 of hazelwood.cs.unca.edu which you can access using the following command from a Linux system.
nc -C hazelwood.cs.unca.edu 33101
Try the following command on any computer supporting telnet. Most Windows platforms do have telnet installed.
telnet hazelwood.cs.unca.edu 33101
Step 4 — Homework 8 — Initializer
The initializer server remembers the first stuff associated with a given key and always returns the same stuff for that key.
For example, suppose there is an initializer running on hazelwood.cs.unca.edu . If you connect to it and send the following line:
swap csci using bestdepartment
If this is the first time a swap has been attempted with the key bestdepartment, the response will be similar to the following:
RETURN csci USING bestdepartment
All subsequent attempts to swap with the key bestdepartment will yield the same response.
There is an initializer running on joe.cs.unca.edu at port 33101.
It is certainly possible for you to write a server that works 99.44% of the
time without using a Lock
object from the
threading
interface.
However, good solutions must provide some way of dealing with
races that could occur when two client connects try to
set the same key and the same time.
Step 5 — Homework 9 — Exchanger
The exchanger server pairs up two clients which wish to exchange stuff for a particular key.
For example, suppose one client connects and sends the following line:
swap Nanci using singer
This client will be blocked, unless there is already another client waiting with the key singer,
Now suppose a second client connects and sends the following line:
swap Iris using singer
Now both clients will be unblocked and will swap their stuff. The first client will receive the message:
REPLACE Iris USING singer
The second client receives the message:
REPLACE Nanci USING singer
You’ll need to use
Condition
and Lock
objects from the
threading
interface on this one.
There is an exchanger running on emma.cs.unca.edu at port 33101.
How much code?
My servers are written in Python.
The definitions of getNetLine
and
putNetLine
are stored in a file where they can
be included from other Python programs. This file contains 17 lines.
My repeater server is 84 lines of Python code. 7 of these lines are blank. 2 lines are used to call the main routine. The main routine creates the server socket, accept new connections, and creates a thread to handle each connecion. The main routine is 26 lines long. About 6 of those lines are used to “reap” threads of inactive connections. I don’t expect most solutions to deal with this.
There is a class handleClient
for handling connections.
This class extends threading.Thread
and is 33 lines
wrong. About one-third of those lines are boring Python, such as
self.addr = addr
There is also an 8-line Python module for reaping inactive threads.
The remaining lines are import
statements and
a recursive expression “compile.”
The initializer and repeater servers are very similar.
The handleClient
class has a single change:
a call to a 10 line function handleExchange
which “remembers” the first input for a key.
handleExchange
uses Python
dictionaries to map keys to value and
locks
for synchronization.
The only differences between the exchanger and initializer
servers are found in the handleExchange
routine.
The exchanger’s handleExchange
is 18
lines long and uses Python
condition variables to make the connection rendez-vous.