Chat Client
Due: February 26
Objective
To gain experience writing a socket program interacting with a server using a protocol.
Task
For this project, you will write a chat client which will connect to a chat server. Your client will allow users to connect to the chat server, create or join chat rooms and chat with other users.
You will connect to a server running at 34.73.23.1 on port 5220. This is a very simple chat server developed for this project. Your chat client should connect to this server and, following the protocol described below, let the user chat with any others logged in.
Note that this server will be used by others in this class, and they can see what you are sending (if theirs is working anyway)!
The Protocol
Right after you connect to the server, you will be in a "lobby" of sorts. At that point you can do one of two things:
- Ask for a list of rooms. To do this, send "/list" to the server. It will then send you back an integer giving the number of existing chat rooms. Next it will send you the names of them all.
- Join a room. To do this, send "/join ROOM" where ROOM is the name of the chat room you wish to join. This can be an existing room, or a new one. The server will send you a "0" to indicate that this was successful, or a "1" to indicate that your request was not formatted correctly.
After the user has joined a room, they must choose a nickname. This can be done by sending "/nick NAME" to the server where NAME is the nickname the user has chosen. The server will send "0" to indicate success, "1" to indicate the request was formatted incorrectly, or "2" to indicate that the name is taken (all nick names in a room have to be unique).
Once they have picked a name, they will be in the chat room. At this point, the server will send the client messages whenever anyone talks. Likewise, the client can send the server a message at any time. These messages will just be plain strings.
From within the room, there are two "special" messages the client can send to the server:
- To ask for a list of users in the room, one can send "/who". Afterwards, the server will send you the names of the users, one after the other.
- To leave the chat room, you can send "/logout". The server will then remove you from the system (you don't go back to the lobby, you just disconnect).
You can assume all messages from the server will be 1024 bytes or fewer. The server makes the same assumptions about what you send.
Requirements
- You client needs to establish a connection to the server.
- Next you should ask the user of your program if they want to list the rooms or join one, and then deal with the server appropriately. If it's not formatted correctly, you must continue to ask them what room to join.
- Next, ask for the user name, and send it to the server. If it is taken, or not formatted correctly, you must continue to ask them for a name.
- Once in the room, you will read from the server, and print any messages received.
- You must also read from the user of the program and send those messages to the server.
- If the user types the "/logout" command, you should close the connection and quit the program after sending it.
You have flexibility in how the interface to your program should work, but you need to make it clear to the user how to do all of these things. You also should not just dump the server messages (like "1" or "2" for errors), but should give a sensible message.
Using select
One issue you will run into with writing the client, is that we must
read from both the server, with our socket, and also the user's input.
The issue is that the socket recv method, and the Python
input function are blocking.
This means code like this won't work well:
# read from server
mesg = sock.recv(1024)
# read from user
in = input()
When recv is called, it will block, meaning it won't return
until the socket actually sends something.  If the socket sends data before the
user, that's OK.  But if not, our code won't get the user's message until the
server sends.  Flipping them in the other order makes a similar issue.
Instead we need to wait for either one to have data available and handle
whichever one is ready first.  This is done with select.  We must
first import the select module.
The function works by taking three lists. The first is the list of things we want to read from. The second is a list of things we want to write to. The third is a list of things we might expect errors on. It returns three lists as well, which are those things which are ready. If we only care about reading from a socket and the user, we can call it like this:
# for the select function
import select
# for the stdin file
import sys
# wait for either our socket or user
reads, writes, errors = select.select([sock, sys.stdin], [], [])
The select function will block until one of the things is ready.  In this
case, when sock and/or sys.stdin are ready to be read.  The reads
variable will be a list of things waiting to be read.  If it contains
sock, then we can recv from the socket.  If it contains
sys.stdin, we can get input from the user right away.
General Requirements
When writing your program, also be sure to:
- Put a comment at the top of your program with your name, the name of the program, the purpose of the program and the honor pledge.
- Put descriptive comments in your code to explain how it is working.
- Test your program thoroughly before turning it in. This will involve running multiple instances of it to see that the instances can communicate!
Submitting
To submit your program, email the program file to ifinlay@umw.edu.