Subscribe
Building a TCP Chat Server with Python's Socket Library

By: vishwesh

Building a TCP Chat Server with Python's Socket Library

In this tutorial, we will be building a TCP chat server using Python's built-in socket library. This tutorial is designed for beginners who want to learn how to build a simple chat server using Python.

What is a TCP Chat Server?

A TCP chat server is a server that allows multiple clients to connect to it and communicate with each other using the Transmission Control Protocol (TCP). TCP is a reliable, connection-oriented protocol that guarantees the delivery of data between two endpoints.

In a TCP chat server, clients connect to the server using a client application, and then send and receive messages to and from other clients connected to the server. The server acts as a mediator, receiving messages from clients and sending them to other clients.

Getting Started

Before we dive into the code, let's make sure we have all the necessary tools installed. For this tutorial, we will be using Python 3.x and a text editor of your choice.

Installing Python

If you don't have Python installed on your computer, you can download it from the official Python website. Make sure to download the latest version of Python 3.x for your operating system.

Choosing a Text Editor

You can use any text editor to write Python code, but we recommend using a text editor specifically designed for coding. Some popular choices include Visual Studio Code, Sublime Text, and Atom.

Setting up the Server

Let's start by creating a new Python file and importing the necessary libraries.

import socket
import threading

Next, we will define some constants that we will be using in our code.

HOST = 'localhost'  # The server's hostname or IP address
PORT = 55555        # The port used by the server

The HOST variable is set to 'localhost', which means that the server will only accept connections from clients running on the same computer. If you want to allow clients from other computers to connect to your server, you will need to set HOST to the IP address of your computer.

The PORT variable is set to 55555, which is an arbitrary number that we have chosen for this tutorial. You can choose any available port number that you like.

Now let's create a function called handle_client that will be responsible for handling messages from a single client.

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

    connected = True
    while connected:
        msg = conn.recv(1024)
        if msg:
            broadcast(f"[{addr}] {msg.decode('utf-8')}")

    conn.close()

This function takes two parameters: conn and addr. conn is the connection object returned by socket.accept(), and addr is the address of the client that has connected to the server.

The handle_client function first prints a message to the console indicating that a new client has connected. It then enters a loop that continuously receives messages from the client using the conn.recv() method.

If a message is received, the function calls a broadcast() function that we will define later. The broadcast() function will send the message to all other clients connected to the server.

Finally, when the loop is exited (which happens when the client disconnects), the function closes the connection using the conn.close() method.

Now let's create a function called start that will be responsible for starting the server and listening for incoming connections.

def start():
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind((HOST, PORT))
    server.listen()

    print(f"[LISTENING] Server is listening on {HOST}:{PORT}")

    while True:
        conn, addr = server.accept()
        thread = threading.Thread(target=handle_client, args=(conn, addr))
        thread.start()

        print(f"[ACTIVE CONNECTIONS] {threading.activeCount() - 1}")

This function creates a new socket object using socket.socket() and binds it to the HOST and PORT variables using socket.bind(). It then listens for incoming connections using socket.listen().

The function enters an infinite loop that continuously accepts incoming connections using socket.accept(). For each new connection, it creates a new thread that runs the handle_client() function using the threading.Thread() constructor. The args parameter is used to pass the conn and addr variables to the handle_client() function.

After starting the thread, the function prints a message to the console indicating that a new client has connected and how many active connections there are.

Broadcasting Messages

Now let's create the broadcast() function that we mentioned earlier. This function will be responsible for sending messages to all clients connected to the server.

def broadcast(msg):
    for client in clients:
        client.send(msg.encode('utf-8'))

This function takes a single parameter, msg, which is the message that we want to send to all clients.

The function then loops through a list of all connected clients and uses the send() method of each client's connection object to send the message. We encode the message using utf-8 before sending it to ensure that it is sent in a format that the client can understand.

Keeping Track of Connected Clients

We also need to keep track of all clients that are currently connected to the server. To do this, we will create a global variable called clients that will be a list of all connected client connection objects.

clients = []

We will then modify the handle_client() function to add the client's connection object to the clients list when the client connects, and remove it from the list when the client disconnects.

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

    clients.append(conn)

    connected = True
    while connected:
        msg = conn.recv(1024)
        if msg:
            broadcast(f"[{addr}] {msg.decode('utf-8')}")
        else:
            connected = False

    clients.remove(conn)
    conn.close()

We first add the client's connection object to the clients list using clients.append(). We then modify the loop to exit when the client disconnects by checking if the recv() method returns an empty byte string. If the loop exits, we remove the client's connection object from the clients list using clients.remove().

Testing the Server

Now that we have implemented all of the necessary code, let's test our server.

Start by running the start() function in your Python file.

start()

This will start the server and print a message to the console indicating that it is listening for incoming connections.

Next, open a new terminal window and run the following command to connect to the server:

telnet localhost 55555

This will connect you to the server using the Telnet protocol. You should see a message in the console indicating that a new client has connected.

Now you can start sending messages to the server. Type a message and press Enter to send it. You should see the message appear in the console of the server, indicating that it has been received and broadcast to all connected clients.

To test the broadcast functionality, open another terminal window and connect to the server using Telnet again. Now when you send a message from one client, you should see it appear in the console of both clients.

Conclusion

In this article, we have learned how to build a simple TCP chat server using Python's socket library. We covered the basics of socket programming, including creating a socket object, binding it to a specific address and port, and listening for incoming connections.

We also learned how to handle incoming connections using threads, how to broadcast messages to all connected clients, and how to keep track of connected clients.

Socket programming can be complex and challenging, but with a solid understanding of the basics, it becomes much more manageable. Hopefully, this article has helped you gain a better understanding of socket programming and how to build a simple chat server using Python.

Recent posts

Don't miss the latest trends

    Popular Posts

    Popular Categories