Creating command-line based Chat Room using Python

Hacker NoonThis post was originally published by Yashraj Singh Chouhan at Hacker Noon

Simple Chat Room using Python

Python is one of the most versatile programming languages and one can observe that through its various applications everywhere. Here is an example of how you can build a simple command-line based chat room using python which is easy to implement and understand. So let’s get started.

What is a chat room?

A chat room is a medium/interface that allows two or more people to chat and send messages to everyone. It can be interpersonal (one-one) and group chat too. In this tutorial, we’re going to build a group chat room that can host more than two clients at a time.

Architecture

For chat room, we’re going to use the server-client architecture. It means multiple clients will be hosted by one server.

Getting Started:

Before diving into code, the last thing we want to know is to follow this architecture, we need to write two scripts, one for the server-side and the other one for the client-side. One thing that needs to be very clear is that clients will talk only via the server. There will be no direct communication between them. So let’s dive into the code.

Server-side code:

Firstly, we’ll be importing two libraries named ‘socket’ and ‘threading’. Both are built-in libraries so there’s no need to pip install them. Just importing will work. Socket programming is a way of connecting two nodes on a network to communicate with each other whereas the threading module provides a very simple and intuitive API for spawning multiple threads in a program. Then we’ll move on to define our IP and port. One needs to know that only unreserved ports can be used as this is going to work on LocalHost and the computer may cause problems if you use the reserved ones.

While defining socket, two parameters named (AF_INET) and (SOCK_STREAM) will be used. The first one indicates the usage of internet socket and the other one indicates the usage of TCP. Then we move on by defining the broadcast function. Its basic function is to send a message to the clients in the clients list. This function is not retiring yet. We are going to use it ahead in other places too. Handling the clients is a pretty tough job, so is the function. It first tries if a message can be received from the client’s end, if yes, it is broadcasted.

But if there’s any kind of error/issue, the server keeps things simple. It simply removes the client. We’ve done a lot of work but, adding the clients still awaits. So let’s do that now. In the receive function, the keyword ‘NICKNAME’ is sent to the clients which means their nickname is requested. Later upon obtaining the nickname, it adds the client to the list.

Well, this loop remains active and multiple clients can join the server. All that you need to have it the right IP and the port address.

Code:

#Coded by Yashraj Singh Chouhan
import socket, threading                                                #Libraries import

host = '127.0.0.1'                                                      #LocalHost
port = 7976                                                             #Choosing unreserved port

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)              #socket initialization
server.bind((host, port))                                               #binding host and port to socket
server.listen()

clients = []
nicknames = []

def broadcast(message):                                                 #broadcast function declaration
    for client in clients:
        client.send(message)

def handle(client):                                         
    while True:
        try:                                                            #recieving valid messages from client
            message = client.recv(1024)
            broadcast(message)
        except:                                                         #removing clients
            index = clients.index(client)
            clients.remove(client)
            client.close()
            nickname = nicknames[index]
            broadcast('{} left!'.format(nickname).encode('ascii'))
            nicknames.remove(nickname)
            break

def receive():                                                          #accepting multiple clients
    while True:
        client, address = server.accept()
        print("Connected with {}".format(str(address)))       
        client.send('NICKNAME'.encode('ascii'))
        nickname = client.recv(1024).decode('ascii')
        nicknames.append(nickname)
        clients.append(client)
        print("Nickname is {}".format(nickname))
        broadcast("{} joined!".format(nickname).encode('ascii'))
        client.send('Connected to server!'.encode('ascii'))
        thread = threading.Thread(target=handle, args=(client,))
        thread.start()

receive()

Client-side code:

This is our second code where we’ll be writing the script for our clients. This code will be enough to get us, multiple clients, without any problem. So we begin with importing socket and threading. After initializing the socket, we need to connect it to the IP and the port. They need to be the same as the server in order to make it functional.

Now we need to connect to the server and if you remember ‘NICKNAME’ was the keyword sent by the server to ask for a nickname, if the client receives that, it sends the nickname and enters the chatroom. But if it fails to receive that keyword, the connection gets lost. Now that we’re connected to the server, why are we waiting, let’s start messaging.

For that, we’ve got the write function that manages the sending of messages. If you wonder what about receiving messages, remember we imported threading. Here it comes into play, we need two threads to begin and that is done.

You’ve noticed that we’ve encoded messages into ASCII before sending, it is because we can send messages only in bytes form and not in string. That’s why always remember, encode before sending and decode after receiving.

code:

#Coded by Yashraj Singh Chouhan
import socket, threading
nickname = input("Choose your nickname: ")

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)      #socket initialization
client.connect(('127.0.0.1', 7976))                             #connecting client to server

def receive():
    while True:                                                 #making valid connection
        try:
            message = client.recv(1024).decode('ascii')
            if message == 'NICKNAME':
                client.send(nickname.encode('ascii'))
            else:
                print(message)
        except:                                                 #case on wrong ip/port details
            print("An error occured!")
            client.close()
            break
def write():
    while True:                                                 #message layout
        message = '{}: {}'.format(nickname, input(''))
        client.send(message.encode('ascii'))

receive_thread = threading.Thread(target=receive)               #receiving multiple messages
receive_thread.start()
write_thread = threading.Thread(target=write)                   #sending messages 
write_thread.start()

Testing in the real world:

Remember, the server will run first, then multiple clients can join in. This can be run in the command-line, but we need different terminals to execute them individually.

Well that’s all for this code, hope you liked it!

Spread the word

This post was originally published by Yashraj Singh Chouhan at Hacker Noon

Related posts