Lab title – Chat room
Learning outcomes – Using Python socket programming to implement a chat room application
In this practical session, we are going to implement a chat room application using Python socket
programming. Unlike peer to peer chat, a chat room means multiple users can connect to a chat
server and send their messages. Every message is broadcasted to every connected chat user. We
need to implement both the chat server and the chat client – the user.
1. Chat server
The chat server should be able to:
Accept connections from multiple clients
Read the messages from each client and broadcast them to all connected clients.
To handle multiple clients, we use the select function from the select module to monitor all sockets.
read_sockets,write_sockets,error_sockets = select.select(rlist,wlist,xlist[,timeout])
The inputs are lists of sockets that we expect to read from (rlist), we expect to write to (wlist), and
can possibly go wrong (xlist). The outputs are subsets of the corresponding lists of sockets that are
ready to read from, ready to write to, and have exceptional conditions. The select function waits
until at least one of the sockets to be ready for processing, or time out.
Use the select function in the chat server:
If any of the client sockets is readable, the server reads the message from that socket and sends the
message to all other client sockets. The broadcast is implemented using the following function:
The following is the full implementation of the chat server. In the code, the server use port 5000 to
listen to for incoming connections. The clients must connect to the same port. You can change the
port number if you want.
# Get the list sockets which are ready to be read through select
read_sockets,write_sockets,error_sockets = select.select(CONNECTION_LIST,[],[])
# Function to broadcast chat messages to all connected clients
def broadcast_data (sock, message):
#Do not send the message to server socket and the client who has sent us the message
for socket in CONNECTION_LIST:
if socket != server_socket and socket != sock :
socket.send(message.encode())
# ChatServer.py
import socket
import select
#Function to broadcast chat messages to all connected clients
def broadcast_data (sock, message):
#Do not send the message to server socket and the client who has sent us the message
for socket in CONNECTION_LIST:
if socket != server_socket and socket != sock :
socket.send(message.encode())
if __name__ == “__main__”:
# List to keep track of socket descriptors
CONNECTION_LIST = []
RECV_BUFFER = 4096 # Advisable to keep it as an exponent of 2
HOST = ”
PORT = 5000
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((HOST, PORT))
server_socket.listen(10)
# Add server socket to the list of readable connections
CONNECTION_LIST.append(server_socket)
print (“Chat server started on port ” + str(PORT))
while 1:
# Get the list sockets which are ready to be read through select
read_sockets,write_sockets,error_sockets = select.select(CONNECTION_LIST,[],[])
for sock in read_sockets:
#New connection
if sock == server_socket:
# Handle the case in which there is a new connection received
sockconn, addr = server_socket.accept()
CONNECTION_LIST.append(sockconn)
print (“Client (%s, %s) connected” % addr)
broadcast_data(sockconn, “[%s:%s] entered room\n” % addr)
#Some incoming message from a client
else:
# Handle data recieved from client
data = sock.recv(RECV_BUFFER).decode()
if data:
broadcast_data(sock,”\r”+’<'+str(sock.getpeername())+'> ‘+data)
else:
# broken socket connection, chat client pressed ctrl+c for example
CONNECTION_LIST.remove(sock)
broadcast_data(sock, “\n Client %s is offline\n” %str(sock.getpeername()))
print (“Client %s is offline” %str(sock.getpeername()))
sock.close()
server_socket.close()
2. Chat Client
The chat client should:
1. Listen to messages from the server.
2. Check the user input. If the user types in a message, send it to the server.
The client has to listen to both the server socket s and the user input – stdin. Again, we use the select
function to monitor the two possible input streams.
Note: The above is not going to work on windows. It uses the select function to read data from both
the socket and the input stream. This works on Linux because Linux treats sockets and file
descriptors in the same manner, therefore the select function is able to read from stdin. On windows
the select function will not read anything except sockets created by the winsock socket functions.
Then the client will do relevant processing depends on which socket is readable. If the server socket
is readable, the client will read the message and print it. If the stdin socket is readable, it means the
user has typed a message to be sent. The client will read the message and send it to the server.
The following is the full implementation of the chat client. Again port 5000 is used in the code.
See next page for the code.
3. Run the chat room on your own computer
Open a console on your computer and run the chat server:
python ChatServer.py
Open multiple consoles on your computer and run the chat client in each console:
python ChatClient.py localhost 5000
You can use 127.0.0.1 instead of localhost.
Now type messages + Enter key from any client console. You are chatting now.
4. Chat with your friends
Group with your neighbours, and nominate one to run the chat server on his/her computer.
Find out the IP address of the server using ~$ifconfig
Everyone in the group run a chat client:
python ChatClient.py ipaddr 5000
where ipaddr is the IP address of the server that you just found.
If the server is running on your computer, then open a new console and run the chat client:
python ChatClient.py localhost 5000
Now start chatting.
socket_list = [sys.stdin, s]
# Get the list sockets which are readable
read_sockets, write_sockets, error_sockets = select.select(socket_list , [], [])
# ChatClient.py
import socket
import select
import string
import sys
def prompt() :
sys.stdout.write(‘
sys.stdout.flush()
#main function
if __name__ == “__main__”:
if (len(sys.argv) < 3) : print ('Usage : python ChatClient.py hostname port') sys.exit() host = sys.argv[1] port = int(sys.argv[2]) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(2) # connect to remote host try : s.connect((host, port)) except : print ('Unable to connect') sys.exit() print ('Connected to remote host. Start sending messages') prompt() try: while 1: socket_list = [sys.stdin, s] # Get the list sockets which are readable read_sockets, write_sockets, error_sockets = select.select(socket_list , [], []) for sock in read_sockets: #incoming message from remote server if sock == s: data = sock.recv(4096).decode() if not data : print ('\nDisconnected from chat server') sys.exit() else : #print data sys.stdout.write(data) prompt() #user entered a message else : msg = sys.stdin.readline() s.send(msg.encode()) prompt() except KeyboardInterrupt: #If user Ctrl+C close the socket politely s.close() print ("Socket to server closed")