Home » Tutorials » How to Create a Chatroom in Python

How to Create a Chatroom in Python

Today, we’re going to make something really cool together: our very own chatroom, using Python. It’s like building a space where friends can chat and hang out online, anytime. This project is a fun way to see what we can do with Python and how it can help us connect with each other.

To bring our chatroom to life, we’re going to work with two main parts: first, we’ll build the ‘heart‘ of our chatroom, which is the Server. This is where all our conversations will live and breathe. Then, we’ll set up the way for friends (or clients, in tech speak) to hop into the chat.

Just a little note: for everyone to chat together, they need to be on the same network. So, let’s not wait any longer and jump right into setting up the server.

Table of Contents

Creating Chatroom Server

Imports

We begin by importing the socket module to establish a connection between our program and a network, enabling clients to access it later.

Next, we import the threading module to allow multiple clients to access our chatroom simultaneously. Finally, we import the datetime module to timestamp the client’s messages.

import socket
import threading
import datetime

Setting Server Address and Port

In this section, we’re going to set up the address and port number for our chatroom server. Imagine the IP address (HOST) as the actual house where our server lives, and the port number as its door. By specifying these, we’re telling our clients exactly where to ‘knock’ (or connect) to join the chat.

HOST = '127.0.0.1'
PORT = 5050

Creating a Server and Binding it to Address

Now that we have established the host address and port number, it’s time to create the server and bind it to them:

First, we’ll create a socket object to handle incoming connections and name it “server“, We’ll use the standard IPv4 addressing (socket.AF_INET) and ensure our socket type uses TCP for reliable two-way communication.

After creating the server, the next step is to bind it to the previously specified HOST and PORT.

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((HOST, PORT))

Initializing Data Structures for Client Management

In this part, we will create two variables:

  • The first, named clients, will initially be empty and is designed to store the names of participants currently in the chatroom.
  • The second, chat_history, will also start empty and is intended to record the clients’ messages within the chatroom.
clients = {}
chat_history = []

Defining Functions

Handle Client Function

When a client connects to our server, this function requests the client to input their username. Once that is completed, it sends the stored chat history to the client, allowing them to catch up on previous messages. Finally, it broadcasts the client’s username to the rest of the chatroom, announcing their arrival.

def handle_client(client, addr):
   print(f"[NEW CONNECTION] {addr} connected.")


   client.send("Enter your username: ".encode('utf-8'))
   username = client.recv(1024).decode('utf-8')
   clients[client] = username


   for message in chat_history:
       client.send(message.encode('utf-8'))


   broadcast(f"{username} joined the Pycodes chatroom.")

Managing Client Communication in a Loop:

This part of the function manages the ongoing conversation by verifying the messages. If the user inputs the command /users, they will receive the current client’s usernames. If the input is a regular message, it is timestamped and added to the chat history, then broadcasted to all clients currently in the chatroom. Additionally, if a client disconnects or an error occurs, they are removed from the chatroom.

   while True:
       try:
           message = client.recv(1024).decode('utf-8')
           if message:
               if message.startswith('/users'):
                   list_users(client)
               else:
                   chat_history.append(f"{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')} ({username}): {message}")
                   broadcast(f"{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')} ({username}): {message}")
           else:
               remove_client(client)
               break
       except:
           remove_client(client)
           break

Defining the Broadcast Function

This function iterates through all the clients in the list, sending them messages and then verifying receipt. If a client does not receive a message, they are removed from the list.

def broadcast(message):
   for client in list(clients.keys()):
       try:
           client.send(message.encode('utf-8'))
       except:
           remove_client(client)

list_users Function

This one displays the active users in the chatroom to the client who requested this information. Specifically, when a user inputs the command “/users“, this function reveals the list of users only to that requesting user.

def list_users(client):
   client.send(f"Online Users: {', '.join(clients.values())}".encode('utf-8'))

remove_client Function

It checks if a client is on the list. If they are, it removes them and broadcasts a farewell message to all other clients.

def remove_client(client):
   if client in clients:
       username = clients.pop(client)
       client.close()
       broadcast(f"{username} left the Pycodes chatroom.")

Defining Start Function

The last one initiates the server we’ve created, setting it to listen on the designated HOST and PORT for incoming client connections. It displays a message indicating that the server is now running.

The checks if the address of incoming clients matches the server’s host address. If there’s a match, the clients are added to the list, and a new thread is started to manage their connection. Finally, we announce that the server is starting.

def start():
   server.listen()
   print(f"[LISTENING] Server is listening on {HOST}:{PORT}")


   while True:
       client, addr = server.accept()
       clients[client] = ''
       threading.Thread(target=handle_client, args=(client, addr)).start()


print("[STARTING] Server is starting...")
start()

Server Full Code

import socket
import threading
import datetime


HOST = '127.0.0.1'
PORT = 5050


server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((HOST, PORT))


clients = {}
chat_history = []


def handle_client(client, addr):
   print(f"[NEW CONNECTION] {addr} connected.")


   client.send("Enter your username: ".encode('utf-8'))
   username = client.recv(1024).decode('utf-8')
   clients[client] = username


   for message in chat_history:
       client.send(message.encode('utf-8'))


   broadcast(f"{username} joined the Pycodes chatroom.")


   while True:
       try:
           message = client.recv(1024).decode('utf-8')
           if message:
               if message.startswith('/users'):
                   list_users(client)
               else:
                   chat_history.append(f"{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')} ({username}): {message}")
                   broadcast(f"{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')} ({username}): {message}")
           else:
               remove_client(client)
               break
       except:
           remove_client(client)
           break


def broadcast(message):
   for client in list(clients.keys()):
       try:
           client.send(message.encode('utf-8'))
       except:
           remove_client(client)


def list_users(client):
   client.send(f"Online Users: {', '.join(clients.values())}".encode('utf-8'))


def remove_client(client):
   if client in clients:
       username = clients.pop(client)
       client.close()
       broadcast(f"{username} left the Pycodes chatroom.")


def start():
   server.listen()
   print(f"[LISTENING] Server is listening on {HOST}:{PORT}")


   while True:
       client, addr = server.accept()
       clients[client] = ''
       threading.Thread(target=handle_client, args=(client, addr)).start()


print("[STARTING] Server is starting...")
start()

Now that we have completed the script for our server, it’s time to move on to writing the script for the client.

Chatroom Client Part

Necessary Imports

We import the socket module to function like a phone that connects us to the server, and the threading module so we can multitask without overloading our program, ensuring it remains responsive.

import socket
import threading

Setting the Server Address and Port

Here, we will define the server’s IP address and port number as constants, allowing the client to access the chat server.

HOST = '127.0.0.1'
PORT = 5050

Creating Socket Connection to Server

In the server code, we created a socket object that functions as the server. Here, we will create a similar socket object, naming it “client“, to connect the client to the server using client.connect((HOST, PORT)).

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((HOST, PORT))

Defining the receive Function

This function enables the user to receive messages from the server continuously. It prints an error message indicating that the connection is closed either when an error occurs or when the connection itself is closed.

def receive():
   while True:
       try:
           message = client.recv(1024).decode('utf-8')
           print(message)
       except:
           print("[ERROR] Connection closed.")
           client.close()
           break

Defining send Function

This one continuously accepts input from the client, encodes it in UTF-8, and then sends it to the server as a message.

def send():
   while True:
       message = input()
       client.send(message.encode('utf-8'))

Creating Threads for Receiving and Sending Messages

These two threads enable the client to send and receive messages simultaneously.

receive_thread = threading.Thread(target=receive)
receive_thread.start()


send_thread = threading.Thread(target=send)
send_thread.start()

Client Full Code

import socket
import threading


HOST = '127.0.0.1'
PORT = 5050


client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((HOST, PORT))


def receive():
   while True:
       try:
           message = client.recv(1024).decode('utf-8')
           print(message)
       except:
           print("[ERROR] Connection closed.")
           client.close()
           break


def send():
   while True:
       message = input()
       client.send(message.encode('utf-8'))


receive_thread = threading.Thread(target=receive)
receive_thread.start()


send_thread = threading.Thread(target=send)
send_thread.start()

Example

To run this code, you simply need to open your command prompt and navigate to the directory containing your Python scripts. Then, execute the server code by typing python name_of_the_server_code_file.py. This command should start the server.

Next, to connect to the chatroom, type python name_of_the_client_code_file.py. This will connect you to the chatroom.

Happy Coding!

RELATED: How to Create a Reverse Shell in Python

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top