Preamble
Some of these questions will be must be handed in for assessment by the end of April 30th. Detailed submission instructions will be added in due course.
Please check back here for last minute updates before submitting your work
There is now a module forum. You need your usual UoL username password to connect; you can post anonymously, or login within the forum using your informatics linux username/password. All posts are moderated, so might not show up immediately.
You should review Lecture 15 for discussion of Socket programming in java and basic client/server architecture.
The deadline for this work is Monday 30th April.
In this page (and in other pages for this module):
Pale yellow boxes indicate code or other material that should be the contents of a file — you will generally use an editor, such as Emacs, Scite or GEdit to enter/view the content.
Pale blue boxes indicate a place where you should be entering a command, e.g. at a command prompt in a terminal window.
Pale pink boxes indicate interactive use, with the input you should type in RED; other text is expected output from a program.
Hints and asides are written in pink italics.
Question 1 — Number Square Service (Unassessed)
Your task is to write a pair of programs, client and server, to implement a number squaring service. This initally be similar to the TimeServer/Client ple discussed in lectures.
You will need to choose a port to run your service on. To get a unique port number, try using your numeric uid. "getent passwd" will tell you your uid (and your gid).
Client
The client uses a Socket to make a connection to the server. Once connected, the client prompts the user for a number (in the console; no need for a GUI), and sends it to the server. The server responds with the square of the number, which the client will print on the screen.
Keep going until the user submits the special number 999. The client should send the special number, then shut down.
Server
Server listens for connections. When a connection is made, it should create a handler Thread which waits for numbers to be sent from the client. After receiving a number, it should calculate the square and send it back to the client.
Repeat until the client sends the special number 999.
Extra features
What happens if the client tries to connect and no server is running?
What happens if one end just stops in the middle (client never sends another number; server never responds to a request)?
Test it over two machines. Try running more than one client against one server.
Test your client with another person's server; and vice versa.
Unassessed — model solution here
Question 2 — Online Voting (assessed)
There is now a module forum. You need your usual UoL username password to connect; you can post anonymously, or login within the forum using your informatics linux username/password. All posts are moderated, so might not show up immediately.
The worksheet is presented in several phases to lead you towards a working solution. If you do not make it to the final phase, you should hand in as far as you have managed. If you do make it to the final phase, you only need to hand that in.
The theme of the exercise is to produce a simple client/server on-line voting system. The server will:
be setup with a fixed candidate list (the BallotPaper) and a list of eligible voters (the VoterList);
accept connections from clients (voters); send the voter a copy of the list of candidates and then record their vote.
It is important that you write your code in a java package called "CO2017.exercise3. This will simplify the marking process. To achieve this, you need to start each code file with a line like this (replaceabc123with your own username).
package CO2017.exercise3.abc123;
If you are using eclipse or a similar IDE, it should have tools available to make it simple to write your code in a specific package, and/or to move code from one package to another.
Phase 0
Download the jar file containing the packageCO2017.exercise3.supportof basic classes for representing Ballots, Ballot boxes and lists of voters. UPDATED (28th March) so it can be imported as library in eclipse. This code forms the packageCO2017.exercise3.support.
See javadoc documentation for the classes included. This describes the public interface provided by the classes. You do not need to implement these yourself.
See test code area for some basic test programs. You can use these to explore the behaviour of the providedCO2017.exercise3.supportpackage, and verify that you have installed them properly.
See also junit test code for some basic junit test programs. Provided for completeness only — you do not need to use these. Working out how to compile and run these junit test cases is left as an exercise for the reader…
Phase 1
In this phase, you will produce simple client and server programs to implement a protocol for online voting. The client and server will make use of the basic data structure classes from Phase 0.
Note that 70% of the CW3 assessment marks are for phase 1.
Protocol
This section describes the protocol that the client and server use to communicate. Note that the messages passed between client and server using the protocol are not necessarily the same as the messages that will be displayed on-screen for the user of the system.
In all cases
vid,bnumare decimal integers (in String form) representing unique voter and ballot identifiers;
voteis a single character vote;
BALLOT,OK,END, etc are literal Strings values;
similarly,Xvid,Xbnum,XvoteandXXXXare values that do not match the expected ones (used in the transaction so far);
values on a single line are separated with colons (':');
lines are to be terminated where shown;
data should be flushed after each message;
{close connection}indicates that the socket connection should be closed
Here are some typical protocol transactions between an individual client and the server.
A typical (no error) vote transaction:
CLIENT SERVER Comment
vid => client requests a ballot
<=
vid:bnum:BALLOT
A:Candidate 1
B:Candidate 2
0:END
server sends back thevid, a new & unique ballot id (bnumand the string "BALLOT"; and then, starting on a new line, the ballot paper, one candidate per line, terminated with "0:END" on a line of its own.
vid:bnum:vote => client sends back the vid, the ballot id, plus the vote
<=
vid:bnum:vote:OK
{close connection}
server sends back the vid, a ballot id, the received vote, plus "OK"; then closes the connection
{close connection}
client closes the connection
Client attempts duplicate vote:
CLIENT SERVER Comment
vid
=> client sends a duplicate voter id (who has already voted)
<=
vid:0:DUPLICATE
{close connection}
server sends back thevid, the special ballot id0(zero) and the string "DUPLICATE"; and then closes the connection
{close connection}
client displays an error message and closes the connection
Vote closing transaction:
CLIENT SERVER Comment
0
{close connection}
=> client sends special zero value and closes the connection
{close connection}
server closes connection and closes the ballot
Incorrect initial response from server:
CLIENT SERVER Comment
vid => client requests a ballot
<=
Xvid:Xbnum:XXXX
server sends back a different voter id OR ballot id OR a string other thanBALLOT
{close connection} client closes the connection (and therefore, so will server) — no vote will be recorded
Incorrect 2nd response from client:
CLIENT SERVER Comment
vid => client requests a ballot
<=
vid:bnum:BALLOT
A:Candidate 1
B:Candidate 2
0:END
server sends back the correct vid, a ballot id, plus the ballot paper, terminated with "0:END"
Xvid:Xbnum:vote => client sends back the something other than the expected voter id OR ballot id OR a vote that is not possible then the vote must be discarded
<= vid:bnum:vote:ABORT {close connection} server aborts the vote and closes the connection
{close connection}
client displays an error message and closes the connection
Incorrect 2nd response from server:
CLIENT SERVER Comment
vid => client requests a ballot
<=
vid:bnum:BALLOT
A:Candidate 1
B:Candidate 2
0:END
server sends back the correct vid, a new & unique ballot id; then, starting on a new line, the ballot paper, terminated with "0:END"
vid:bnum:vote => client sends back the vid, the ballot id, plus the vote
<=
Xvid:Xbnum:Xvote:XXXX
{close connection}
server records the vote, but then (for some reason) sends back an incorrect response (one or more of voter id, ballot number, vote or the "OK" message are wrong) and closes the connection
{close connection}
display a warning to voter about the incorrect response from the server and then close the connection
I/O streams
To avoid confusion, all data should be sent asStringvalues. Do not useDatareaders/writers to send numbers. You should use something very like this (on both ends of the connection):
BufferedReader rdr = new
BufferedReader(new InputStreamReader(server.getInputStream(), "UTF-8"));Writer out = new OutputStreamWriter(server.getOutputStream());
Make sure that strings you write are terminated (with"\r\n"or, if using formatted strings, with"%n").
Make sure youflushthe output buffer after finishing each transaction.
You can then usereadLineto read in complete lines on the other end of the connection.
Phase 1A: Simple client —Voter.java
This is a simple interactive client, for use in a command line terminal. For ple, here are several successive invocations of the simple client program:
$ java CO2017.exercise3.gtl1.Voter localhost 8111Connected to localhost/127.0.0.1
Enter voter id: 12341234: 1
A:E.Smith (Apple Affiliates)
B:B.Jones (Android Alliance)
C:A.Brown (Microsoft Party)
D:D.Green (Blackberry Bunch)
E:C.Black (Penguinistas)
Enter vote: EVote processed OK
$ java CO2017.exercise3.gtl1.Voter localhost 8111Connected to localhost/127.0.0.1
Enter voter id: 12351235: 2
A:E.Smith (Apple Affiliates)
B:B.Jones (Android Alliance)
C:A.Brown (Microsoft Party)
D:D.Green (Blackberry Bunch)
E:C.Black (Penguinistas)
Enter vote: DVote processed OK
$ java CO2017.exercise3.gtl1.Voter localhost 8111Connected to localhost/127.0.0.1
Enter voter id: 14321432: 3
A:E.Smith (Apple Affiliates)
B:B.Jones (Android Alliance)
C:A.Brown (Microsoft Party)
D:D.Green (Blackberry Bunch)
E:C.Black (Penguinistas)
Enter vote: EVote processed OK
$ java CO2017.exercise3.gtl1.Voter localhost 8111Connected to localhost/127.0.0.1
Enter voter id: 1432
When invoked, the server hostname and port are supplied as command line arguments.
The client then prompts the user for their candidate number. This is sent to the server, which responds with a string representation of the ballot paper, which should be printed out. Assume that valid voter numbers are between 1000 and 1999 (inclusive).
The client then prompts the user for their vote (a single character), which is sent to the server.
The special voter id number of 0 (zero) causes the server to shut down.
Code to submit:
Voter.java(if you complete phase 3, just hand in the phase 3 version along withVoteClientHandler.java)
Assessed: 35% of the assessment
Phase 1B: Simple Server —PollServer.java
The server is invoked with a port number to listen on, plus the name of a file containing the candidate list (ple file here). It should start up and listen for incoming client requests. Each request should result in a separate handler thread being started to deal with the connection.
Your Poll should have a voter list with voter ids between 1000 and 1999 inclusive.
ple behaviour:
$ java CO2017.exercise3.gtl1.PollServer 8111 candidates.txt Vote client /127.0.0.1:57903 connected.
Voter /127.0.0.1:57903 requests ballot for: 1234
Sent ballot paper number 1 for 1234
Got vote: E
Vote client /127.0.0.1:57907 connected.
Voter /127.0.0.1:57907 requests ballot for: 1235
Sent ballot paper number 2 for 1235
Got vote: D
Vote client /127.0.0.1:57910 connected.
Voter /127.0.0.1:57910 requests ballot for: 1432
Sent ballot paper number 3 for 1432
Got vote: E
Vote client /127.0.0.1:47818 connected.
Voter /127.0.0.1:47818 requests ballot for: 1432
Code to submit:
PollServer.java(if you complete phase 2, just hand in the phase 2 version along withVoteHandler.java)
Assessed: 35% of the assessment
Phase 2: Multi-threaded server —VoteHandler
YourPollServerfrom section 1B can only handle a single voter client at a time. In this phase you will extend it to be able to handle multiple concurrent connections.
To do this write aVoteHandlerclass that implements theRunnableinterface. Each instance will deal with a single vote on the server side.
Modify yourPollServerclass so that for each new client connection, it creates a newVoteHandlerinstance and starts it in its own thread.
Test your server by starting multiple instances of the client at the same time (perhaps using different hosts). For maximum marks multiple clients should all be able to communicate with the server concurrently.
To control the vote handler threads, you can either control them yourself (by just invoking thestartmethod); or you can setup a ThreadPoolExecutor, as seen in Exercise 2.
You will find one of hardest parts is to close thePollServerwhen the special voter id 0 is sent. The normal pattern is that a handler is created for each new connection as soon as it is made (which is before you know what the voter id is). This means that the main server loop may be blocked runningserver.accept(), waiting for a new client connection even though the Ballot is closed (and therefore no more votes will be coming).
To get around this problem, you can set a timeout on the socket (pseudo-code):
do {
server = new ServerSocket(port);
server.setSoTimeout(10000); // 10s timeout
try {
Socket client = server.accept();
... // Do something with the socket if a connection is made
}
catch (SocketTimeoutException e) {
if (stopCondition) break; // exit the loop if stop condition is met
// otherwise, continue with the loop
}} while (true);
Code to submit:
VoteHandler.java
Assessed: 20% of the assessment
Phase 3: Bulk voting
Your simple client (Voterclass) has to interact with the end-user twice:
to read in the voter id who is going to vote;
to display the ballot and read in the voter's choice.
In phase 3, you will convert the client to a self-contained vote handler that uses call-backs to get these external bits of information.
VoteClientinterface
The VoteClientinterface, is part of theCO2017.exercise3.supportpackage that you have already downloaded and installed. Actual clients must implement this interface in order to provide the needed callbacks.
VoteClientHandler(implementsRunnable)
Produce a class that can run a single voter client as a thread. You will need to implement these public methods:
VoteClientHandler(Socket s, VoteClient vc)
Constructor. Set upBufferedReaderandWriterinstances attached to theSocket
void run()
Implement the client functionality as described in phase 1A. Use thegetVid()andgetVote(BallotPaper bp)callbacks from theVoteClientobject to provide the voter id and the voter's actual vote.
Re-implement simpleVoterclass
Re-implement the simpleVoterclass from phase 1A using yourVoteClientHandlerclass. You will need to make yourVoterclass implement theVoteClientinterface by providing these methods:
int getVid()must prompt the user for their voter id;
char getVote(BallotPaper bp)should display the ballot paper to the user and read in their vote.
Themainmethod of your improvedVoterclass will simply attempt to connect to the server, and then immediately create and start aVoteClienthandlerthread. Since this is a simple client that only needs to handle a single vote, you can then just usejointo wait for the handler to finish.
Bulk client:VoteStuffer
Use yourVoteClientHandlerclass to implement a bulk voting program. It should read in voter identifiers and votes from from a file.
You will need to make yourVoteStufferclass implement theVoteClientinterface by providing these methods:
int getVid()must return the next voter id from the file;
char getVote(BallotPaper bp)can ignore theBallotPaperand just return the next vote from the file.
Note that for each voter, the VoteStuffer program will open a new connection to the PollServer.
Initially you can just work through the file of votes sequentially. But for maximum marks you should use aThreadPoolExecutorto run multiple voters concurrently.
ple of theVoteStufferin action:
$ java CO2017.exercise3.gtl1.VoteStuffer localhost 8111 votes.txt1029:B
Vote processed OK
1329:B
Vote processed OK
1042:A
Vote processed OK
1042:A
1042 has already voted; VOTE REJECTED
0:X
Closing voting on localhost
$
The input file should contain entries one vote per line: "vid:vote" wherevidis a voter number, andvoteis that voters single character vote.
Here is a program you can use to generate suitable input files: GenVoteList.java. Note that:
the generated list ends with a vote "0:X" in order to force the closure of the Poll;
the generated test file will not contain any duplicates.
Code to submit:
Voter.java
VoteClientHandler.java
VoteStuffer.java
Assessed: 10% of the assessment
Assessment and submission
Overall: 15% of MODULE mark
Submission
Your complete solution should be in the specified source files. It is acceptable to use additional local classes within the source files specified.
If you do not complete all phases, you should hand in as far as you have managed. For ple, if you have working code for phase 2, and partial but non-working code for (say) phase 3, then submit the working code using the handin system, and use the "notes" section to mention the extra work; you can email the non-working code to me directly if you wish.
PLEASE check back here prior to submitting your work in case there are any last minute updates.
Static evaluation
Your work will be assessed on both functionality (with dynamic testing using various input parameters, see below), and statically on matters of layout and coding style, including, but not limited to:
Use of comments, including clear identification of the author.
Appropriate choice of identifier names (variables, etc).
Where class, method and attribute names are specified, you should stick precisely to the specification.
Where output strings are specified, you should conform to the specification. Generally you should not include output that is not explicitly required.
Indentation and spacing.
See the style guidelines for more details.
Dynamic testing
Your code will be tested using a linux environment very similar to that on the linux machines in the CS department labs.
NB: your code should compile successfully with simple invocations of "javac" at the command line.
It is important that your classes provide the specified interfaces exactly as described as each class will be tested in isolation, or against the "reference" implementation (in other words against the model answer).
Phase 1A: Basic client class
YourVoterclass will be compiled and tested against the reference implementation of the thePollServerclass.
Phase 1B: Basic server class
YourPollServerclass will be compiled and tested against a test class that submits multiple votes sequentially.
Phase 2: Multi-thread server class
YourPollServerandVoteHandlerclasses will be compiled and tested against a reference version of theVoteStufferclass.
Phase 3
YourVoteStufferclass will be compiled and tested against the reference implementation of thePollServerandVoteHandlerclasses.