For this lab, you will implement a chat program that allows you to exchange messages between computers without the need for a central server. The technique we will use is known as peer-to-peer networking. Instead of connecting to a central server, all users serve as both clients and servers in the network. Joining the network at any point connects you to all users in the network. Peer-to-peer networking introduces many of the interesting challenges in distributed systems, some of which you will need to think about at the end of this lab.
To get started, download the starter code archive p2pchat.tar.gz
.
The starter code includes an implementation of a simple user interface built using ncurses. To start the program, run the following command:
$ ./p2pchat student
This will replace your terminal window with a display that has two fields.
When you type, you should see text appear in the lower field.
If you hit enter, the message you typed should appear in the upper field, and the lower input field should be cleared.
To exit, type the command :quit
and hit enter.
Verify that all of this interface works before moving on.
The functions that build and update this user interface are declared in ui.h
, and implemented in ui.c
.
You should not need to review the implementation in any detail, but you may want to refer to the comments in ui.h
.
If you look at p2pchat.c
, you will see basic uses of all the user interface functions.
At startup, the program calls ui_init(input_callback)
.
This function initializes the user interface and registers a callback function.
The callback function is run every time the user presses enter in a non-empty input field.
After initializing the user interface, the starter code calls ui_run
.
This function does not return as long as the program is actively running.
Any other work you need to do while the user interface is running will have to happen in other threads.
If you move up to the input_callback(const char* message)
function, you can see the other two interactions with the user interface.
This function runs each time the user types in a message and hits enter.
In the normal case, the starter code passes this message on to the display using the ui_display
function.
However, if the message was :quit
or :q
, the starter code calls ui_stop
.
This causes the ui_run
function to return, and the program will exit.
Your task for this lab is to implement a network chat system using this starter code.
Unlike the previous network programs you wrote, this program will not have separate server and client programs.
Instead, every p2pchat
program will serve as both a client and a server.
Every time you start a chat program it will create a server socket and listen for incoming connections.
Any peers that connect to the current program are joining the chat network.
To start a new chat network, run the command:
$ ./p2pchat student
If you specify a peer on the command line, the program will also connect to that peer to join an existing chat network. The starter code includes some basic code to access the command line arguments, but does not include any of the networking code. To start a program and join an exiting network, run the command:
$ ./p2pchat other-student turing.cs.grinnell.edu 54321
Of course you will need to replace turing.cs.grinnell.edu
with the name of the machine you want to connect to, and 54321
with the port number the existing peer is listening on.
We will spend time in class to look at some example collections of peers in a chat network. Regardless of how the network is structured, all users in the network should receive messages sent from any other point in the network. To implement this, you will need to handle two cases:
It is up to you to determine how you send messages, but make sure you include both the username and message text in the data you send over the network.
While we used file streams in our previous exercise, you may find it easier to use read
and write
to access the network.
We’ll talk about a simple use of these functions in class.
Complete your implementation and verify that it can forward messages through the network. Make sure to test several network structures. Some possible cases include: all peers connected to one central peer, a tree-shaped network with a root peer, and peers arranged in a straight line. Your program should work regardless of the structure.
One you have completed your implementation, you will need to answer four questions in the QUESTIONS.txt
file included with the starter code.
Write your answers in this file and included it with the p2pchat.c
file when you submit your lab.
The questions are:
What kinds of faults can your peer-to-peer chat implementation tolerate? Faults may include problems with machines or the network, as well as program crashes. Be specific about what failure situations you could tolerate, and explain how the system can continue to work in the face of these failures.
What faults will cause your peer-to-peer chat to fail, or to operate in some diminished capacity? Again, be specific about the situations that will result in failure.
One mechanism for tolerating failure is replication. If each client connected to two existing peers instead of just one, would that help you tolerate any additional faults? What problems could this change create for your implementation?
Describe one additional change you could make to the peer-to-peer chat system that would allow it to tolerate faults. Describe how you would implement this change, and at least one example of how it would allow you to tolerate a fault.
Your response to each question should be at least four sentences long, though you will likely need to write more than that to give sufficient detail.