How to Make a Chat Room Application in Python?

Posted in /  

How to Make a Chat Room Application in Python?
vinaykhatri

Vinay Khatri
Last updated on April 19, 2024

    In a Chat Room Application, two or more clients connected to the server and chat with each other. The server fetches the messages from one client and shares them with other clients so all the clients could communicate with each other.

    To build a Chat Room in Python we need to create only two scripts. The first script will be the server script that will handle all the messages from the clients and broadcast the messages and the second script would be the client script, which will be used by clients to connect with the server and send messages.

    In this tutorial, I will be using my local system as a server which means my server would be the localhost, and all the clients will also run locally on this system. Before we implement our Chat Room using Python let's discuss the modules we will be using in this tutorial.

    Required Modules

    For this tutorial, we will be using two Python standard libraries.

    Python socket

    socket is one of the Python inbuilt modules, and it is widely used to perform socket programming in Python. Using the socket modules we can set the connection between two nodes network. For this tutorial, we will use socket programming to set server and clients and communicate them with each other.

    Python threading

    Python threading module is used to simulate multi-threading in Python. Although actually Python does not support multi-threading because of GIL lock, but threading module allows us to simulate the execution of threads concurrently.

    Both the modules socket and threading are available for Python so we do not need to install them separately. Now let's start coding our server and client scripts.

    Server Script with Python

    First, we need to write our Python server script, that will handle all the clients and broadcast(share) message amongst them. In our server script, we will create three modules:

    • broadcast_message() will share messages amongst all the connected clients.
    • message_manager() will receive messages from the clients.
    • connection() will manage both the messages and show the connected clients.

    Now let's start coding the server script We will begin with importing the required modules.

    import socket
    import threading
    Define the HOST address and PORT number on which we want to set the server.
    HOST = '127.0.0.1'   #localhost
    PORT = 50000  # anyport

    As I have already mentioned that, I will be using my localhost as a server that's why I have specified '127.0.0.1' as a HOST address. The PORT number 50000 is arbitrary, you can take any port Number between 5000 to 100000 according to your system.

    Now let's set the server socket instance that will listen to all the connections coming to the HOST address and PORT number.

    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)    #socket instance
    
    server.bind((HOST, PORT))
    server.listen()   #listen incoming connection
    
    clients = []
    client_names =[]

    The socket.socket(socket.AF_INET, socket.SOCK_STREAM) function will create an instance of the socket as a server . The bind() function will bind the server socket instance to the specified host and port number.

    Next, the listen() function will listen to all the calls made on the specified HOST and address. The clients and client_names are the two lists that will store all the connected clients and their user names respectively.

    Now let's define a Python function that will share the message between the clients.

    def broadcast_message(message):
        for client in clients:
            client.send(message)

    The broadcast_message() function accepts the message as an argument and shares the message among all the connected clients, including the client that has sent the message. The send() function is used to send the message.

    Now define the message_manager() function that receives the message from the client and calls the broadcast_message() so all the connected clients can see the message.

    def message_manager(client):
        while True:
            try:
                message = client.recv(1024)   # receive  the message
                broadcast_message(message) 
            except:
                index = clients.index(client)
                clients.remove(client)
                client.close()
                client_name = client_names[index]
                print(f"Client {client_name} Disconnected!".encode('ascii'))
                client_names.remove(client_name)
                break
    

    In the try block, we will read the client message using client.recv(1024) function. 1204 argument represents the number of message bytes that should be read.

    Once we read the message we can share it with other clients using broadcast_message() function. The message_manager() function's except block handle if the client leaves the server.

    When the client closes its terminal or leaves the server we will remove the client and its username from the clients and client_names list.

    Now let's define the connection() function that will handle the complete server by running the clients and their messages in different threads.

    def connection():
        while True:
            client, address =server.accept()
            print(f"{address} Connected[+]")
            client.send("UserName".encode('ascii'))
            client_name =client.recv(1024).decode('ascii')
    
            client_names.append(client_name)
            clients.append(client)
    
            print(f"{client_name} Connected[+]")  #on server
            message = f"{client_name} Connected[+]".encode('ascii')   
            broadcast_message(message)       #send message to every client
    
            client.send("You are connected to server".encode('ascii'))
    
            thread = threading.Thread(target=message_manager, args=(client,))
            thread.start()
    server.accept() will return the connected client object and its address. For this tutorial, the address would be the same for all the clients.
    Once the client is connected we will ask for its user name using client.send("UserName".encode('ascii')) statement. And grab the client entered Username using client.recv(1024).decode('ascii') statement.
    The client_names.append(client_name) and clients.append(client) will append the client name and client object in the client_names and clients list.
    broadcast_message(message) statement will send the New user-connected message to every connected client.
    client.send("You are connected to server".encode('ascii')) statement will send a Connected private message to the connected client.
    threading.Thread(target=message_manager, args=(client,)) statement will call the message_manager() function when the species client send some message.
    Now we need to call the connection() function so our server could start running.
    print("Server[127.0.0.1] localhost is running.... ")
    connection()
    Now put all the code together and we need to execute it before we execute our client script.

    Python Server Program for Chat Room

    #server.py

    import socket
    import threading
    
    HOST = '127.0.0.1'   #localhost
    PORT = 50000  # anyport 
    
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)    #socket instance
    
    server.bind((HOST, PORT))
    server.listen()   #listen incoming connection
    
    clients = []
    client_names =[]
    
    def broadcast_message(message):
        for client in clients:
            client.send(message)
    
    def message_manager(client):
        while True:
            try:
                message = client.recv(1024)   # receive  the message
                broadcast_message(message) 
            except:
                index = clients.index(client)
                clients.remove(client)
                client.close()
                client_name = client_names[index]
                print(f"Client {client_name} Disconnected!".encode('ascii'))
                client_names.remove(client_name)
                break
    
    def connection():
        while True:
            client, address =server.accept()
            print(f"{address} Connected[+]")
            client.send("UserName".encode('ascii'))
            client_name =client.recv(1024).decode('ascii')
    
            client_names.append(client_name)
            clients.append(client)
    
            print(f"{client_name} Connected[+]")  #on server
            message = f"{client_name} Connected[+]".encode('ascii')   
            broadcast_message(message)       #send message to every client
    
            client.send("You are connected to server".encode('ascii'))
    
            thread = threading.Thread(target=message_manager, args=(client,))
            thread.start()
    
    print("Server[127.0.0.1] localhost is running.... ")
    connection()

    Client Script with Python

    We have done with the Server script, now we need to write the client script that will be used by the client to connect with the server, send and read messages. I have divided the client script into two major modules:

    • read_messages() will receive the messages from the server.
    • write_message() will send the messages to the server.

    In our client script, we first need to import the required modules and set the connection for the localhost and port number on which our server script is running.

    import socket
    import threading
    
    HOST = '127.0.0.1'   
    PORT = 50000  
    
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    
    client.connect((HOST, PORT))
    username= input("Please Enter a User Name: ")
    
    socket.socket(socket.AF_INET, socket.SOCK_STREAM) statement will set a socket instance based on the TCP connection. The connect() function will connect the client to the server HOST and port number. Using the input("Please Enter a User Name: ") statement we will ask the client to set a readable username.

    Now let's define a function read_message() that will read or print all the messages on the terminal sent from other users and also send the Entered username to the server for when the client connected to the server for the first time.

    def read_message():
        while True:
            try:
                message = client.recv(1204).decode('ascii')    #receive messgae from server
                if message =="UserName":
                    client.send(username.encode('ascii'))
                else:
                    print(message)
            except:
                print("Error!")
                client.close()
                break

    client.recv(1204).decode('ascii') will receive the message from the server. The send(username.encode('ascii')) will send the Entered username to the server if the message is encoded to Username or when the user connected to the server for the very first time.

    The try block will show the message if everything goes well if the client closes its terminal or left the server the except block close the client using close() function. Now let's create a write_message() function that will help the user to write and send messages to the server.

    def write_message():
        while True:
            message = f"{username}: {input(': ')}"
            client.send(message.encode("ascii"))     #send message to server
    

    The send() function will send the encoded message to the severe. Now we need to call the read_message() and write_message() function using threads so multiple users can send the messages concurrently, instead of one after another.

    read_thread = threading.Thread(target=read_message)
    read_thread.start()
    
    write_thread = threading.Thread(target=write_message)
    write_thread.start()
    Now put the code together and execute after executing the server.py script.
    import socket
    import threading
    
    HOST = '127.0.0.1'   
    PORT = 50000  
    
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    client.connect((HOST, PORT))
    username= input("Please Enter a User Name: ")
    
    def read_message():
        while True:
            try:
                message = client.recv(1204).decode('ascii')    #receive messgae from server
                if message =="UserName":
                    client.send(username.encode('ascii'))
                else:
                    print(message)
            except:
                print("Error!")
                client.close()
                break
                    
    def write_message():
        while True:
            message = f"{username}: {input(': ')}"
            client.send(message.encode("ascii"))     #send message to server
    
    read_thread = threading.Thread(target=read_message)
    read_thread.start()
    
    write_thread = threading.Thread(target=write_message)
    write_thread.start()

    Output

    To see the output you can open three terminals or command prompts, out of which one needs to be the server and the other two could be clients. Do not execute the client.py script before the server.py script always executes the server first. When you execute the server script on one terminal and two clients script on two other terminals you will be able to create a Chat room.

    Conclusion

    Now let's sum up the above article. To create a chat room in Python you need to create two different scripts one for the server and another for the client. To set the communication between the server and client we use Python socket programming along with multi-threading, so there would no lag between the message send and message read. You can copy and paste the above two scripts, run them on your local machine and it would work as expected.

    Here in this article, I have used the LocalHost to set the server and clients, if you have a dedicated server or router on which you want to set the server, you only need to change the HOST address and the PORT number.

    People are also reading:

    Leave a Comment on this Post

    0 Comments