Assignment 3

Due February 26, 2016 11:59pm via sakai

Supplemental information

Objective

Your goal in this assignment is to write a multi-threaded TCP sockets-based messaging system. You will write one server and two command-line clients:

  • Server: stores all messages
  • Post client: post a new message to a group
  • Get client: retrieve all messages from a specific group

Languages

You may do this assignment in C, C++, Java, or Python.

Groups

You may work on this assignment either individually or in a group of up to four members. Your work will be judged to a higher standard if you have more group members. With a group of four, for example, I expect flawless program execution, cleanly formatted code with good comments, and a report with detailed test cases explained that is so beautifully written that I will weep tears of joy upon seeing it.

Deadline

Be sure to allot sufficient time to do this assignment. If you are comfortable with programming, you should be able to finish this assignment within an hour. Do not assume that, however. You may find yourself spending a lot more time than you budgeted in parsing requests and responses, formatting a date, or wondering why your client is not connecting to your server.

Develop incrementally. Take a look at the recitation notes as an example of how you can add tiny amounts of code and then test it. Do not write a few hundred lines of code and then try to debug it. That is a recipe for disaster.

Be aware that there is an exam coming up soon as well as possible other projects and activities in your life. Start early and budget your time. Make sure that you allot enough time for testing and writing your report.

Background

First be sure that you understand sockets programming. The textbook covers basic examples using Python. We covered sockets using Java in recitation and you can consult the notes in the Supplemental information section above for a walkthrough in Java and C along with example code. There are also numerous resource on the web.

Requirements: post client

The post client allows you to post a message to a specific group on the server. The command line accepts an optional -h followed by the server’s host name, an optional -p followed by the server’s port number, and a mandatory group name:

post [-h hostname] [-p port] groupname

If a hostname is missing, use “localhost” as the default name. The name localhost is a reserved name that refers to the local computer and accesses the network via the loopback network interface, bypassing the network hardware. DO NOT hardcode the name of any specific host. Chances are high that I will not be using that host in my testing. If a port number is missing, use a hard-coded default port number that is the same as the default port that your server uses (a number in the range 1024 through 65535).

Examples of valid command lines are:

post -h ls.cs.rutgers.edu -p 3311 notices
post -h ls.cs.rutgers.edu jokes
post -p 3311 garbage
post stuff

The command will be invoked in a manner that makes sense to the environment. For example, if the assignment is written in java, you would run

java post -h ls.cs.rutgers.edu -p 3311 notices

or, if programming in python

python post.py -h ls.cs.rutgers.edu -p 3311 notices

Any invalid command line should result in an error message and the program exiting with an exit status of 1.

After the client connects to the server, it will read from the standard input and send all bytes read to the server, where they will constitute a new message for that group. For example:

echo "What do you call a bear with no teeth? -- A gummy bear!" | post -h ls.cs.rutgers.edu jokes

or

post -h null.cs.rutgers.edu -p 30123 test <<!
This is just a test.
It is a test message to a test group.
!

Of course, you can just type a message after running the post command and end it by typing whatever your end-of-file character is. Note that your client should not check for any specific end-of-file character but should just detect an end of file condition on the input stream since end of file characters only make sense to, and are processed by, the terminal driver.

Post protocol specification

The post client follows the following protocol.

post-protocol
post-protocol

Once the command line is parsed and validated, the client sends a post command to the server that contains the name of the group. This is a text message containing the string “post” followed by one or more spaces, the group name, and a newline characger (‘\n’). The group name contains only printable characters and no white space (you may assume the ASCII character set; see the FAQ).

The server either accepts or rejects this request and sends a response back to the client. This is a newline-terminated line of text. If the response starts with the string “error”, the remainder of the line contains the error message. The client will print this message and exit. If the response is the string “ok” then the client continues on.

Next, the client sends the user’s ID name. This is the user’s login name. In Java, you can obtain this via a call to

System.getProperty("user.name")

This call is not foolproof since it reads an environment variable but it is portable and good enough for the assignment. If you’re using C, you can get the login name as a string (char *) via a call to

getlogin()

The server validates the syntax of the commnd and the user name to ensure that it is a string of printable text and returns either an error message or an “ok” message. Again, the client prints any returned error and exits.

Otherwise, the client now reads from the standard input and writes everything it reads to the socket. Once it receives an end of file on the input stream, it closes the socket and exits.

Requirements: get client

The get client allows you to retrieve all message from a specific group on the server. Just like the post command, the get command line accepts an optional -h followed byt the server’s host name, an optional -p followed by the server’s port number, and a mandatory group name:

get [-h hostname] [-p port] groupname

If a hostname is missing, use localhost as the default name. If a port number is missing, use a hard-coded default port number that is the same as the default port that your server uses.

Examples of valid command lines are:

get -h grep.cs.rutgers.edu -p 3311 notices
get -h vi.cs.rutgers.edu jokes
get -p 3311 garbage
get stuff

Any invalid command line should result in an error message and the program exiting with an exit status of 1.

After the client connects to the server and sends its request, it will receive message count followed by a list of messages for that group. Each message is preceded with a header that identifies when it was posted, from where, and by whom. For example:

$ get -h ls.cs.rutgers.edu jokes
2 messages
From paul /192.168.60.142:58713 Fri Feb 05 16:13:14 EST 2016

What do you call a bear with no teeth? -- A gummy bear!

From paul /192.168.60.132:42786 Fri Feb 05 16:15:38 EST 2016

If at first you don't succeed,
destroy all evidence that you tried.

When the client has no more content to read from the server, it exits.

Get protocol specification

The get client follows the following protocol.

get-protocol
get-protocol

Once the command line is parsed and validated, the client sends a get command to the server that contains the name of the group. This is a text message containing the string “get” followed by one or more spaces, the group name, and a newline characger (‘\n’). The group name contains only printable characters and no white space.

The server either accepts or rejects this request and sends a response back to the client. This is a newline-terminated line of text. If the response starts with the string “error”, the remainder of the line contains the error message. The client will print this message and exit. If the response is the string “ok” then the client continues on.

Next, the client receives a message count. This tells it the number of messages that are present in that particular group. This information will be parsed and presented to the user but the count does not need to be used in any way since the server then sends a stream of message headers and messages. The client simply prints every byte it receives from the server until it receives an end of file on the socket. At that time, it closes the socket and exits.

Requirements: Server

The server implements the server side of the protocols defined above. the server command line accepts an optional -p followed by the port number:

server [-p port]

If the port number is not provided, use a hard-coded default port number that is the same as the default port that your clients use.

The server waits for incoming TCP connections from clients. The server is multi-threaded and can handle multiple concurrent requests.

Upon receiving a command from a client, the server checks to see if it is a get or post command. If it is anything else, it returns a string stating:

error: invalid command

and closes the connection.

It then validates the group name to ensure that the name contains only printable text. A bad name results in a return message of:

error: invalid group name

Group management

The server does not have to persist its contents into files. All data can be kept in memory. You will need to have the server keep track of any number of groups and any number of messages within a group. Each message will be identified by the creator’s IP address, port number, user name, and timestamp.

Post requests

If a group name is valid but does not exist, the server creates the group and initializes its message count to zero. The server then reads the id directive, validates the command, and validates the username to ensure that it is a string of printable characters.

The server is now ready to receive the message. It stores the source IP address and port (you can store them as one string if you use Java’s getRemoteSocketAddress()) method), the user name, and the timestamp for this new message. It then reads data from the socket. Every byte read becomes part of the message. Once the server receives an end-of-file on the socket, it closes the socket and terminates the message.

Get requests

When the server receives a get request, it first validates the syntax of the request. If the group name is not a valid format or the group does not exist, the server responds back with:

error: invalid group name

If the group does exist, the server responds back with a message count and then, for each message, sends:

  1. A header of the format “From username host:port timestamp” For example:

    From paul /192.168.60.142:58713 Fri Feb 05 16:13:14 EST 2016

  2. A blank line

  3. The message (which may span an arbitrary number of lines)

  4. A blank line only if there is another message

When there are no more messages to send, the server closes the connection.

Submission

Submit everything I need to compile your program. At a minimum, you will submit a writeup and three source files: the two clients and one server.

Report

Your report can be brief and can be in plain text or pdf. Be sure that it contains the following:

  1. Names of all group members
  2. Precise and detailed instructions for compiling and running the programs. I suggest that you test these out on your friends and make sure that they work exactly. I will not have the patience to fiddle with getting your program compiled and running and you will lose a huge percentage of the grade if I cannot compile and run it.
  3. A discussion of the data structures you use to manage your groups.
  4. Any bugs or peculiarities.
  5. A discussion of the tests that you ran. These should include tests to ensure that concurrency works correctly (multi-threading) and that proper syntax is enforced.

Source code

Submit only the source code for your assignment. Do not include executables, C object files, or Java class files. Do not include any temporary files.

Make sure that every file has the names of the group members in it.

Make sure that the code looks clean. Indentations should be consistent; do not mix leading tabs and spaces. Use clear variable names. You do not need a lot of comments but be sure to have a comment that identifies each function or method in your program.

Make sure that your code does not have confusing debugging statements or blocks of commented-out code. Basic server-side messages, such as indications that you received a connection and what commands you are parsing, are fine.

Submit

Before uploading your files to sakai, make sure that all the components are there. If we can’t compile it (or can’t figure out how to), you will lose virtually all credit for the assignment.

Hand the assignment in via sakai.

Only one group member should submit the assignment. You will be penalized for duplicate submissions.