Introduction
he Wolfie Chat program will allow users logged into the the Wolfie Chat server to send messages to each other. Chats between users will each be displayed on the client machine in independent windows, just as Google Hangouts does.
Clients will attempt to establish a connection with the server through the accept thread. The accept thread on the server will create a connection with the Client and spawn the Login Thread. The Login thread will then communicate with the client via the Wolfie Protocol to successful/unsuccessfully log the user into the Wolfie Chat system. Upon successful/unsuccessful login, the Login thread will terminate. A Login thread will be created for each connection attempt and terminated upon completion. Multiple login threads can exist simultaneously if multiple users are attempting to login.
If the user is successfully logged on, then the server will act as the middle man for all communications between the users connected to the server. A Communication thread on the server will be spawned when the first user logs onto the server and terminate when no user is logged in. This thread will then service all additional users who connect. An overview of the architecture is shown below.
Part I - Establishing a connection
In this part we will work on establishing a simple login procedure between the client and server program. At the end of it you should have multiple users logged in who can simply ask the server “how long have I been connected”. The server should then respond to the correct user and let them know how long. Also the client should be able to ask “who else is connected” and the server will return a list of connected users. Once this part is completed, you should be able to extend the concepts to make a more complex application which will allow users connected with the server to communicate with each other.
Server
Below is a diagram representing the internal control flow of the server program. As discussed above this is the main accept thread which is running when the server program is run. Login threads are spawned as necessary to handle each user’s login attempt. A successfully logged in user then communicates with the server via the communication thread.
Accept Thread (main())
The primary server program will accept commands from the user via stdin and connections from the client program via the bound “listen” socket. When the server accepts an incoming connection from a client it should spawn a new login thread and begin the login process. If it detects input from the keyboard, it should parse that input for a list of commands and handle it accordingly. This section of the process will use a form of I/O multiplexing to listen for input on both the server socket and from stdin.
I/O multiplexing is exposed via the following interfaces - select, poll, or epoll. They all have their pros and cons, but it is up to you to choose which technique you should use. You will use I/O multiplexing in both the server and your client program. In your server, you will multiplex on each socket for the connected users in the communication thread, and in the accept thread you will multiplex on the accept socket and stdin.
The benefits of I/O multiplexing are that the program will be put into a suspended state while no activity is being performed on the fd’s, and when one of the fd’s is written to, it will alert your program that something happens, and you can then act on it. The other benefits to these techniques is that they work in a synchronous manner, but allow you to have behavior similar to doing things concurrently, without the overhead of spawning new threads, or starting new processes.
Login Thread
When a client connects to the server, the server should spawn a thread to handle the login protocol with the server. The login protocol is defined later in Part I. The Login thread will need to check the list of users on the server (shared resource between server threads) to see if the username is already in use. If the name is not in use, the login thread will then complete the protocol to log the user into the server. We will simply treat login for this part as a first come first serve process. If student1 logs in as user1 then student2 tries to login as user1, student1 will successfully log in and student2 will be rejected. Any relevant data about the connecting user should be a of structure you define that makes their information easily accessible. An in-exhaustive list of things relevant to save are: the time of login, the socket on which they communicate, the username, and the ip address. You are encouraged to add any other fields of data that assist in your implementation.
Communication Thread
When there is at least one user logged in to the server a thread must be spawned to handle the communication to and from the server and later between all of the clients. In your communication thread you will use I/O multiplexing on the set of file descriptors (fds) used to communicate with the clients.
You must use I/O multiplexing.
Server commands
Aside from handling connections from various clients, the server also has to handle input from stdin. This input should represent commands that the person operating the server might want to use. These commands are transparent to the clients connected and are mainly used as a way to gather information by the server operator.
/users
When /users is typed into the server’s terminal it should dump a list of currently logged in users to stdout (NOTE: this does not send anything over the network, this is only on the server side.). This can be a great way to debug your program, it is advised you take some time to make neatly formatted print statements that print out relevant data. (Think, toString() function for your user structs).
/help
When /help is typed into the server’s terminal it should list all the commands which the server accepts and what they do.
/shutdown
When /shutdown is typed into the server’s terminal it should cleanly disconnect all connected users. Save any state that it must and then close all the sockets and files which it is using and free any heap memory allocated.