How to Create a Chat Room in Python?
Date: 28 June 2020
In this article we will be making a simple chat room in Python. This will be very simple to build with only a little more than 100 lines of Python code. But first we need to understand some simple concepts - sockets and threading.
Sockets
We will start with the most basic question i.e., What are sockets?
Sockets are internal endpoints for sending and receiving data on a computer network identified using the IP address and port number.
The definition is pretty simple if we know what a port number is. A port number is a 16-bit unsigned integer which is used to identify different processes a computer is performing on a network. We can use almost any port number from 0 to 65535 except some which are associated with some common processes already running on our system. Check out the list here.
Threading
If you have ever researched about the processors you already know what a thread is and can skip this part. For others I will try to explain in the simplest way I can.
To run several processes simultaneously, we use the technique of multi-threading in which we assign each process a thread and our OS switches between tasks to give the illusion that the processes are running simultaneously. Similarly, when a user has joined our chat server we will be creating a new thread for it.
Our chat room will have two scripts - one will be the server which will be running continuously and the other will be the client which we will use to communicate.
server.py
We will start by importing some necessary modules.
import socket
import _thread
import sys
We will discuss them briefly one-by-one but you can check the official documentation to read more.
First, socket and _thread is used to create sockets and threads respectively for our server and clients. sys is used for I/O operations.
Now, we will create a socket for our server.
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
The arguments I have used here are the default recommendations as provided in the documentation.
The below lines of codes will help process the arguments we will provide while executing our script i.e., our private IP address and port number.
if len(sys.argv) != 3:
print("Correct usage: script, IP address, port number")
exit()
IP_address = str(sys.argv[1])
Port = int(sys.argv[2])
# Binding the server to the entered IP address and port number.
# The clients must know these parameters to connect
server.bind((IP_address, Port))
# Listens for maximum 10 active connections.
# This number can be changed accordingly.
server.listen(10)
list_of_clients = []
Next, we will define a function to operate each client.
def clientthread(conn, addr):
conn.send(b"Welcome to this chatroom!")
while True:
try:
message = conn.recv(2048)
if message:
# To convert byte object to string
message = message.decode(encoding='UTF-8')
print("<" + addr[0] + "> " + message)
message_to_send = "<" + addr[0] + "> " + message
broadcast(message_to_send, conn)
else:
remove(conn)
except:
continue
conn is an object of server class and represents a client. In the first line we have sent a welcome message to the client using the send method.
One thing to note, the send method takes a byte object as parameter instead of a string that’s why we have used the b identifier in front of our welcome message. Also, we will be using encode and decode methods of the string class for the same.
Next, in the infinite loop we have a try-except block which will help wait for a client's message and whenever any client has sent some message it will receive it using the recv method which will be printed on the server’s terminal and further broadcasted to all other clients using the broadcast function which we will be defining next.
def broadcast(message, connection):
for clients in list_of_clients:
if clients != connection:
try:
# To convert string object to byte object
message = message.encode(encoding="UTF-8")
clients.send(message)
except:
clients.close()
remove(clients)
In this function we are simply iterating over the list of connected clients and sending the message to each of them. The remove function is another user-defined function which will remove unavailable clients from the list_of_clients list.
def remove(connection):
if connection in list_of_clients:
list_of_clients.remove(connection)
This is possibly one of the simplest functions which will remove the client received as parameter from the list.
while True:
conn, addr = server.accept()
list_of_clients.append(conn)
print(addr[0] + " connected")
_thread.start_new_thread(clientthread, (conn, addr))
This final infinite loop will help us establish new client connections and create new threads using start_new_thread method.
conn.close()
server.close()
Finally, we will close the sockets and the server we created to free ports for other processes.
Now, we just need to make the client-side script and then we can have fun with our Chat Room.
client.py
Again, we will start by importing necessary modules.
import socket
import select
import sys
We have already discussed these except select which is used for interfacing with the underlying operating system.
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if len(sys.argv) != 3:
print("Correct usage: script, IP address, port number")
exit()
IP_address = str(sys.argv[1])
Port = int(sys.argv[2])
server.connect((IP_address, Port))
This is the same as the server.py script. We have created a socket for our client and connected it with our server using the IP address and port number we have provided as arguments.
while True:
sockets_list = [sys.stdin, server]
read_sockets, write_socket, error_socket = select.select(
sockets_list, [], [])
for socks in read_sockets:
if socks == server:
message = socks.recv(2048)
message = message.decode(encoding="UTF-8")
print(message)
else:
message = sys.stdin.readline()
message_bytes = message.encode(encoding="UTF-8")
server.send(message_bytes)
sys.stdout.write("<You>")
sys.stdout.write(message)
sys.stdout.flush()
This infinite loop is simply looking for messages from the server which if received will be printed or if the user inputs a message through the terminal it will send that message to the server.
server.close()
At last, we will close our client’s socket.
And Voila we have just built our very own chat room.
We can execute the server-side script by
python3 script.py <local_ip_of_server> <port_number>
And client-side script by
python3 client.py <local_ip_of_server> <port_number>
You can get the complete scripts here.
Here is the little chat I had with myself using two computers.
Note: My one PC has the local IP of 192.168.1.2 which I will be using as the server and a client and my other PC which will be the other client has IP 192.168.1.12. Similarly, you can connect as many PCs you want.
This is the server I made. I am using port 5000 but you can use any available port.
This is my first PC which is starting the conversation.
This is the second PC.
If you face any problems, hit me up with an email and we will try to figure it out together.